Compare commits

..

220 Commits

Author SHA1 Message Date
Dylan Hunn 2ea541f4f8 release: cut the v13.3.4 release (#45702)
PR Close #45702
2022-04-20 14:31:12 -07:00
Andrew Kushnir dd7eeb6929 fix(docs-infra): avoid internal symbols from being referenced during auto-linking (#45689)
This commit adds extra logic to avoid internal and privately exported symbols from being referenced during auto-linking. Currently such symbols can be used for linking, thus resulting in a non-existing link and causing the linking process to fail.

PR Close #45689
2022-04-20 09:11:22 -07:00
Paul Gschwendtner 1d204fcf2c Revert "test(common): Fix flaky Location test (#45683)" (#45691)
This reverts commit 254d6cea9a.

This test has only been introduced in the next branch with
https://github.com/angular/angular/pull/44901. The cherry-pick
of the flaky test fix does not work in the patch branch due to
some other missing changes and the test did not exist in 13.3.x
anyway.

PR Close #45691
2022-04-20 08:58:46 -07:00
Paul Gschwendtner 7619c16697 build: preparation for primary branch rename in the Angular repos (#45691)
Preparation for the framework repo as outlined our planning
document.

PR Close #45691
2022-04-20 08:58:46 -07:00
Mangalraj 52a564df94 docs: Update aio/content/guide/setup-local.md (#45644)
Co-authored-by: George Kalpakas <kalpakas.g@gmail.com>
PR Close #45644
2022-04-19 20:20:40 -07:00
Mangalraj bb7b51bbc6 docs: correct the example command to install angular (#45644)
PR Close #45644
2022-04-19 20:20:40 -07:00
Andrew Scott 254d6cea9a test(common): Fix flaky Location test (#45683)
This test has proven to be flaky. This commit greatly simplifies the
test and moves it to a more appropriate location (pun intended).

PR Close #45683
2022-04-19 20:17:56 -07:00
Saurabh Kamble 1e8fe84c05 Fix typo (#45680)
PR Close #45680
2022-04-19 09:26:14 -07:00
George Kalpakas 22ef5e0e60 docs(common): fix links to locales in i18n guides (#45661)
In PR #42230, the locale file generation process was modified so that
generated locale files are no longer checked into the repository. Update
a few links in the docs that pointed to the previously checked in files
to point to other places where the files exist.

PR Close #45661
2022-04-19 09:17:34 -07:00
Jeremy Elbourn c4e1d45418 build: don't assign jelbourn to most review categories (#45668)
Configure pullapprove to not automatically assign jelbourn to most review categories.

PR Close #45668
2022-04-19 09:15:40 -07:00
Louis Gombert d5a522a40a docs: update decorators proposal stage and link in glossary (#45669)
PR Close #45669
2022-04-19 09:14:37 -07:00
Andrew Kushnir ed832b4dd7 test: reset counters before running a styling test (#45670)
This commit updates one of the styling tests to reset perf counters, making it order-independent and non-flaky (previously the test got random failures depending on whether there are other tests invoked before).

PR Close #45670
2022-04-19 09:14:10 -07:00
Marko Kaznovac ebf98c4695 docs: use language agnostic mdn urls (#45666)
PR Close #45666
2022-04-18 14:10:17 -07:00
Marko Kaznovac ac8c896fff docs: fix mdn links (#45666)
PR Close #45666
2022-04-18 14:10:17 -07:00
dario-piotrowicz 37b3ac7f69 fix(docs-infra): implement focus trap for aio search results (#45654)
currently if a user tries to navigate via keyboard, once the are
presented with search results, the search results panel remains
present and can potentially hide most of the content on the page,
in such case keyboard navigation will be severly hindered and
the only option for the user would be to go back to the seach input
text and clear its value, fix such inconvenience by looping the
focus in the header area close to the search results and the
results panel itself

note: an alternative implementation using the cdkTrapFocus has been
attempted in PR #45194, such alternative implementation presented a
number of (minor) drawbacks (including the increase main bundle size
due to the inclusion of the A11yModule), so it was agreed to proceed
with the manual implementation present in these changes instead.

PR Close #45654
2022-04-18 09:57:53 -07:00
dario-piotrowicz b5820b6fa4 fix(docs-infra): fix aio search-results issue with toolbar and notification (#45579) (#45654)
use border-top-width instead of padding-top as the strategy for moving
the search-results panel down, this fixes the issue of the panel going
behind the toolbar (which causes either overlapping text in the home
page or the results scrollbar to be hidden behind the toolbar in other
pages)

PR Close #45579

PR Close #45654
2022-04-18 09:57:53 -07:00
dario-piotrowicz 26fe7642fe fix(docs-infra): amend notification close button aria-label (#45579) (#45654)
move the aria-label used inside the close-button to the button itself
(since otherwise the button's aria-label overrides the childs)

PR Close #45579

PR Close #45654
2022-04-18 09:57:53 -07:00
dario-piotrowicz 1564771b3a feat(docs-infra): add close button to search-results aio panel (#45579) (#45654)
add a close button to the search-results aio panel so that the user can
conveniently close it via keyboard

this complements the focus trap implemented in PR #44989
(more here: https://github.com/angular/angular/pull/44989#issuecomment-1037287678)

PR Close #45579

PR Close #45654
2022-04-18 09:57:53 -07:00
Andrew Kushnir 989ba8fb65 ci: add more reviewers to the docs-packaging-and-releasing group (#45652)
Currently that group has just 2 reviewers, but we often update the files that belong to that group during the deprecation period. Adding more people would allow to balance the reviews better.

PR Close #45652
2022-04-18 09:24:59 -07:00
Kristiyan Kostadinov 9317f513d5 fix(core): better error message when directive extends a component (#45658)
We throw an error when a directive is trying to extend a component, but we don't actually say which class is responsible which can be difficult to track down. These changes add the two class names to the error message.

PR Close #45658
2022-04-18 09:24:24 -07:00
ivanwonder d68333e508 fix(language-service): two-way binding completion should not remove the trailing quote (#45582)
We allow the path to contain both the `t.BoundAttribute` and `t.BoundEvent` for two-way
bindings but do not want the path to contain both the `t.BoundAttribute` with its
children when the position is in the value span because we would then logically create a path
that also contains the `PropertyWrite` from the `t.BoundEvent`. This early return condition
ensures we target just `t.BoundAttribute` for this case and exclude `t.BoundEvent` children.

Fixes https://github.com/angular/vscode-ng-language-service/issues/1626

PR Close #45582
2022-04-15 13:53:49 -07:00
Andrew Kushnir 4766817f02 fix(core): improve multiple components match error (#45645)
This commit improves the error message that is thrown at runtime when multiple components match the same element. Now the error message contains names of classes that represent those components.

PR Close #45645
2022-04-15 13:52:20 -07:00
Andrew Kushnir 575cafc163 test(core): add a test for multiple named interpolations with the same name (#45651)
The test from this commit verifies that i18n logic can handle multiple named interpolations with the same name.

PR Close #45651
2022-04-15 13:51:56 -07:00
Ilya Marchik acbd2e9339 docs: fix typo (#45637)
Replace wrong mention of 'heroService.delete()' with 'heroService.deleteHero()' because 'heroService.delete()' doesn't exist and 'heroService.deleteHero()' should be mentioned instead

Resolves #45636

PR Close #45637
2022-04-14 16:30:05 -07:00
Andrew Kushnir a1c741846d docs: move old changelog entries to a separate file (#45639)
This commit moves all release notes for everything before v11.0.0 to a separate file, so that the changelog can be rendered correctly via GitHub UI.

Closes #45635.

PR Close #45639
2022-04-14 15:01:49 -07:00
George Kalpakas 8d09451d89 docs(core): fix typo in View Encapsulation code example (#45629)
Fix closing tag name to match opening one (`</hero-detail>` -->
`<hero-details>`).

PR Close #45629
2022-04-14 15:00:06 -07:00
Andrew Kushnir ec115a31b8 refactor(core): avoid referencing PlatformRef in bootstrap code (#45519)
This commit updates an existing bootstrap logic to avoid referencing the `PlatformRef` instance to keep track of the platform status. Instead, we use platform injector, so that the `PlatformRef`can be tree-shaken away in the bootstrap logic for Standalone Components.

The motivation for this change is that retaining the `PlatformRef` class also retains NgModule-based bootstrap code, which would not be needed in case of Standalone Components.

PR Close #45519
2022-04-13 15:34:48 -07:00
Jessica Janiuk cbfe6284a2 release: cut the v13.3.3 release (#45614) 2022-04-13 11:27:48 -07:00
Kristiyan Kostadinov e50fd9ee87 fix(compiler): avoid errors with extremely long instruction chains (#45574)
Our logic for generating code from an AST uses recursion which limits the number of expressions we can nest before we reach the call stack limit. These changes add a limit in order to avoid errors in some cases where the chains become extremely long.

Fixes #45564.

PR Close #45574
2022-04-13 16:18:56 +00:00
4javier 5fe59706fd docs: fix grammar (#45455)
PR Close #45455
2022-04-12 23:55:33 +00:00
4javier cfb54c6a7b docs: fix to comply with new codeblock guidelines (#45455)
PR Close #45455
2022-04-12 23:55:33 +00:00
4javier 14268012ad docs: modified as per dylhunn suggestions (#45455)
https://github.com/angular/angular/pull/45455#pullrequestreview-925369970
PR Close #45455
2022-04-12 23:55:32 +00:00
4javier db7201fd84 docs: update template reference variables (#45455)
- Specify `NgForm` gets applied by default on `<form>` elements before the long example using it
- Move the strange (and questioned in a commented line) snippet about undefined ref vars in a standalone paragraph and clarify its meanings (adding the part about directive just because there was something similar already there)
- Extend and modify `*ngFor` example, since in the original that was misleading to think reference variable couldn't be used inside a loop
- Remove two lines stating that with `*ngIf` and `*ngFor` the framework cannot know if a template is ever instantiated (can't see how this relate with the page)
- Add an explanation of assignment of default `$implicit` value to undefined input variables
- Modify template example for template input variable to be a complete ngForOf loop instead of the original poor intelligible truncated one
- Replace last generic statements about variable namespaces with a more pragmatic and explanatory one concerning the resolution in case of homonymy

PR Close #45455
2022-04-12 23:55:32 +00:00
Andrew Kushnir fc145d024b refactor(core): make ComponentFactoryResolver lazily instantiated in ApplicationRef (#45507)
This commit removes the `ComponentFactoryResolver` as a constructor argument of the `ApplicationRef` class. This makes it lazily instantiated + simplifies further refactoring in a context of Standalone Components.

PR Close #45507
2022-04-12 22:29:17 +00:00
Andrew Kushnir 44b9d89917 refactor(core): make platform core providers tree-shakable (#45506)
This commit refactors the set of hardcoded platform core providers into tree-shakable providers.
In addition to making them tree-shakable, this would also avoid the need to rely on the platform creation logic in an upcoming bootstrap logic for Standalone Components.

PR Close #45506
2022-04-12 22:28:24 +00:00
Jason Hendee ae1db7a88d docs: make tutorial instructions consistent (#45372)
When starting this tutorial, it's not clear to the user whether they should add routing right away, Etc. The other tutorials within the routing section do a better job of this.

Also.. the suggested name of this sample app clashes with that of a previous tutorial, forcing the user to either delete the previous tutorial files, choose a different name for this tutorial's app, or place this app in a different parent directory.
 Conflicts:
	aio/content/guide/router-tutorial-toh.md

PR Close #45372
2022-04-12 22:27:38 +00:00
Dylan Hunn 5c9fe8de29 build: only allow renovate to run on Monday nights (#45605)
By running renovate once a week, we can consolidate all the updates into a single weekly PR, before each Wednesday release. That will significantly reduce the burden on caretakers, and make patch ports less onerous.

PR Close #45605
2022-04-12 22:26:49 +00:00
Virginia Dooley c49d23269c docs: new Pipes custom data doc (#45505)
PR Close #45505
2022-04-12 21:29:07 +00:00
Virginia Dooley 24212cd7ef docs: pipes custom data transform (#45505)
PR Close #45505
2022-04-12 21:29:07 +00:00
4javier d5b7c9610d docs: fix path typo (#45604)
PR Close #45604
2022-04-12 21:27:49 +00:00
4javier ddd822fdc5 docs: fix final code review section codetabs path (#45604)
Fix paths for codetabs in final review section messed up by this commit https://github.com/angular/angular/commit/42289f25c69ec7a36d2e3ef424d32f77bc7cd19a
They were all pointing to `heroes-search.component`
PR Close #45604
2022-04-12 21:27:49 +00:00
Michael-Doner d31f4de575 docs: add powershell execution policies note (#45576)
Fixes #44598

PR Close #45576
2022-04-12 21:13:59 +00:00
George Kalpakas 5900f0e133 docs(docs-infra): add missing period in aio/README.md (#45584)
PR Close #45584
2022-04-12 18:40:46 +00:00
Joe Martin (Crowdstaffing) 61894570f1 docs: improve markdown (#45590)
improve markdown for documentation. Duplicate of #45325 that targets 13.3.x.

PR Close #45590
2022-04-11 22:35:01 +00:00
Renovate Bot 09c5c18c7d build: update dependency google-closure-compiler to v20220405 (#45568)
PR Close #45568
2022-04-11 16:26:26 +00:00
Michal Materowski f09d16600b build: fix typo in package.json file comment (#45569)
Change comment in scripts section of package.json

PR Close #45569
2022-04-11 16:14:16 +00:00
George Kalpakas 1b2c67d9fd test(docs-infra): fix e2e test for {@example} dgeni tags (#45551) (#45563)
Previously, the `guide/compoent-style` page was used in e2e tests to
verify the behavior of `{@example}` dgeni tags. However, this guide has
been updated and no longer contains an `{@example}` tag.

This commit switches to using a different page (`api/common/NgIf`) that
does currently contain an `{@example}` tag.

(NOTE: This will also fix the [CI failures][1] in #45501.)

[1]: https://circleci.com/gh/angular/angular/1145424

PR Close #45551

PR Close #45563
2022-04-08 15:55:25 +00:00
George Kalpakas 2144b997fa fix(docs-infra): add shell to the list of code-example languages recognized as cli commands (#45551) (#45563)
Previously, only `language="sh"` and `language="bash"` would be
recognized (and formatted) as cli commands in `<code-example>`.

This commit adds `shell` to the list of languages recognized as cli
commands.

(NOTE: This will fix the [CI failures][1] in #45325.)

[1]: https://circleci.com/gh/angular/angular/1145559

PR Close #45551

PR Close #45563
2022-04-08 15:55:24 +00:00
Cédric Exbrayat 208d81921d refactor(core): validate property (#45528)
Simplifies and documents the `validateProperty` function (in a similar fashion that #45492 simplified `validateElementIsKnown`).

PR Close #45528
2022-04-07 22:03:13 +00:00
George Kalpakas 18f98e671b docs: remove out-of-order <h3> elements from footer (#45510)
The footer uses `h3` elements out of order, which causes a "Heading
elements are not in a sequentially-descending order" a11y error.
Replace the `h3` elements with `div` to improve a11y.

Fixes #44338

PR Close #45510
2022-04-07 21:01:58 +00:00
Hossein Mousavi dbd6e75b37 docs(forms): remove the incorrect set value from previous commit (#45533)
in the validators documentation, the value for the formControl for both required and requiredTrue validators is an empty string. This is OK for required since it gives us an error. But I think if we set the value of formControl responsible for requiredTrue to something other than an empty string (e.g.: 'some value'), it would demonstrate the difference between required and requiredTrue better.

PR Close #45533
2022-04-07 21:00:26 +00:00
Hossein Mousavi 6a5ee688df docs(forms): add value to formControl for better demonstration of requiredTrue validator (#45533)
in the validators documentation, the value for the formControl for both required and requiredTrue validators is an empty string. This is OK for required since it gives us an error. But I think if we set the value of formControl responsible for requiredTrue to something other than an empty string (e.g.: 'some value'), it would demonstrate the difference between required and requiredTrue better.

PR Close #45533
2022-04-07 21:00:26 +00:00
Andrew Kushnir fb5e16e018 release: cut the v13.3.2 release (#45548) 2022-04-06 08:47:13 -07:00
Andrew Kushnir 05121c0381 test(animations): update test to use an object instead of a Map (#45531)
The code in the patch branch is slightly different from the master branch: the master branch contains some changes where Map are used instead of objects in animations. As a result, one of the tests is failing in patch, since it expects Maps, but receives objects.

PR Close #45531
2022-04-05 10:31:48 -07:00
Christoph Guttandin a92bceda54 test(animations): add test for buildAnimationAst() function (#31107)
This commit adds a test for the buildAnimationAst() function.

PR Close #31107
2022-04-05 08:41:40 -07:00
Christoph Guttandin b46b25c562 fix(animations): handle structured AnimateTimings (#31107)
This commit makes sure structured AnimateTimings are not procesed any further when building the AST.

Fixes: #22752

PR Close #31107
2022-04-05 08:41:40 -07:00
Renovate Bot fc86fe5dad build: update dependency entities to v4 (#45509)
PR Close #45509
2022-04-04 14:54:17 -07:00
Cédric Exbrayat 9fcc1b7758 refactor(core): validate element is known in JIT mode (#45492)
Renames, simplifies and documents the function in charge of validating if an element is known in JIT mode.

PR Close #45492
2022-04-04 09:34:42 -07:00
Alan Agius ca7a143376 fix(docs-infra): update Angular packages to latest minor version (#45502)
This is needed because Angular CLI 13.3 contains fixes that are needed for Stackblitz Node 16 to compile Sass. We also added `copyfiles` in `aio/tools/examples/shared/package.json` as `yarn sync-deps` was failing due to the missing dependency.

PR Close #45502
2022-04-04 09:23:55 -07:00
piyush132000 5db99cae22 docs: add animations to readme file (#45488)
Updated readme file for adding animations topic in advance topics of Angular

PR Close #45488
2022-04-04 09:17:50 -07:00
mgechev a3d9c82ca4 docs: change roadmap updated date (#45500)
PR Close #45500
2022-04-01 13:33:08 -07:00
mgechev c21b68dcb8 docs: add details about ssr efforts (#45500)
PR Close #45500
2022-04-01 13:33:08 -07:00
Dylan Hunn 9c9a52540c release: cut the v13.3.1 release (#45485)
PR Close #45485
2022-03-30 14:21:53 -07:00
JoostK 7f53c0f4ac fix(compiler-cli): handle inline type-check blocks in nullish coalescing extended check (#45478)
This commit fixes an inconsistency where a type check location for an inline
type check block would be interpreted to occur in a type-checking shim instead.
This resulted in a missing template mapping, causing a crash due to an unsafe
non-null assertion operator.

In the prior commit the `TcbLocation` has been extended with an `isShimFile`
field that is now being used to look for the template mapping in the correct
location. Additionally, the non-null assertion operator is refactored such
that a missing template mapping will now ignore the warning instead of crashing
the compiler.

Fixes #45413

PR Close #45478
2022-03-30 11:34:41 -07:00
JoostK 3f55567111 refactor(compiler-cli): track whether a TcbPosition corresponds with a shim file (#45478)
Extends `TcbPosition` with a field that indicates whether the `tcbPath` is a
type-checking shim file, or an original source file with an inline type check
block.

This field is used in an upcoming commit that fixes an inconsistency with how
inline type check blocks are incorrectly interpreted as a type-checking shim
file instead.

PR Close #45478
2022-03-30 11:34:41 -07:00
JoostK fa90c74a73 refactor(compiler-cli): rename ShimLocation to TcbLocation (#45478)
Inline type check blocks (TCBs) are emitted into the original source file, but
node positions would still be represented as a `ShimLocation` with a `shimPath`
corresponding with the type-checking shim file. This results in inconsistencies,
as the `positionInShimFile` field of `ShimLocation` would not correspond with
the `shimPath` of that `ShimLocation`.

This commit is a precursor to letting `ShimLocation` also represent the correct
location for inline type check blocks, by renaming the interface to
`TcbLocation`. A followup commit addresses the actual inconsistency.

PR Close #45478
2022-03-30 11:34:41 -07:00
JoostK 09f8883826 test: update size golden to account for backport conflict (#45480)
The backport in #45473 introduced a change in payload sizes that is not met on
the 13.3.x branch, this commit corrects this issue.

PR Close #45480
2022-03-30 11:34:10 -07:00
AlirezaEbrahimkhani 7ab7734582 docs: add Angular university website to resources list (#45437)
PR Close #45437
2022-03-29 17:13:09 -07:00
Willian Corrêa 5061c4d41d Update aio/content/marketing/resources.json (#45076)
Co-authored-by: Alan Agius <alan.agius4@gmail.com>
PR Close #45076
2022-03-29 17:11:55 -07:00
Willian Corrêa 3b22121c38 docs: add Rangle's Angular Training book (#45076)
PR Close #45076
2022-03-29 17:11:55 -07:00
Andrew Kushnir 9c03b6371a docs: adding a missing close tag in AIO template (#45474)
Commit 6e45777f01 introduced a change where 1 closing tag was accidentally removed. This commit adds that tag back.

PR Close #45474
2022-03-29 16:46:24 -07:00
Dylan Hunn 6e45777f01 docs: patch port of #45376 (#45473)
PR Close #45473
2022-03-29 15:36:17 -07:00
Paul Gschwendtner 70006daac4 test: update aio payload size golden to reflect Angular update (#45469)
Updates the AIO payload size goldens to reflect the Angular update
affecting both the `aio` and `aio_local` build (due to CLI devkit
changes affecting both goldens, and the Angular update also affecting
the non-local `aio` build / job).

Patch-port of 6e1fce529a

Aside from AIO, the forms integration test size golden also
needs to be updated. A zonejs change caused the 500 bytes limit
to be exceeded. The change landed in `master` without exceeding,
but exceeded in the `13.3.x` branch (unrelated to the Angular
update). Manually confirmed by diffing the bundles that this change
is the culprit.

https://github.com/angular/angular/commit/c08705899f538bd2d26475c94c2832631c16977b

PR Close #45469
2022-03-29 13:13:08 -07:00
Paul Gschwendtner 63539489da test: update api goldens to reflect api-golden bazel rule change (#45469)
The API golden Bazel rule has changed in the shared dev-infra code. Instead
of putting golden API reports into the golden folder as per their original
location in the NPM package, golden reports are now stored based on the
package exports. This makes it more obvious how entry-points are consumable

As part of this change, since the API golden rule now consutls the NPM package
`exports` field, the `localize/tools` entry-point golden file is now generated.

Previously it wasn't generated due to it not having a secondary entry-point
`package.json` file. Such package json files should not be needed anymore
and will be gone in future APF versions.

PR Close #45469
2022-03-29 13:13:08 -07:00
Renovate Bot f7c9ac16ea build: update angular (#45469)
PR Close #45469
2022-03-29 13:13:08 -07:00
dario-piotrowicz 7bbf009216 fix(docs-infra): update a11y min-scores (#45209)
update (decrease) the value of some of the accessibility MIN_SCORES_PER_PAGE
after recent changes

PR Close #45209
2022-03-29 09:23:14 -07:00
dario-piotrowicz 0b96c37986 fix(docs-infra): assign different aria labels to main aio navs (#45209)
assign different aria labels to the primary nav and the one used for
guides and docs, so that impaired users can more easily distinguish the
two

PR Close #45209
2022-03-29 09:23:14 -07:00
dario-piotrowicz 9a82067c03 fix(docs-infra): remove redundant main roles (#45209)
remove redundant main role as pages should always have a
single element with a main role (also remove the role assigne
to the main tag as that is implied)

PR Close #45209
2022-03-29 09:23:14 -07:00
dario-piotrowicz 14cabb00d2 fix(docs-infra): wrap the main aio mat-toolbar in a header (#45209)
wrap the main aio mat-toolbar in a header element to provide better
accessibility

resolves #16938 (the first point)

PR Close #45209
2022-03-29 09:23:14 -07:00
dario-piotrowicz a1d9ce80f6 fix(docs-infra): remove navigation role to aio-top-menu ul (#45209)
currently the navigation ul used in aio-top-menu has a role of
navigation, but listitems should be owned by list parents
(see more: https://www.w3.org/TR/wai-aria-1.1/#listitem)
so wrap the ul in a nav and remove the role="navigation" from the
ul element to fix such issue

resolves #44562
resolves #16938 (the second point)

PR Close #45209
2022-03-29 09:23:14 -07:00
Andrew Kushnir 52e036a193 docs: add image directive to public roadmap (#45448)
PR Close #45448
2022-03-28 10:30:26 -07:00
JiaLiPassion c08705899f fix(zone.js): should ignore multiple resolve call (#45283)
Close #44913

The following case is not handled correctly by `zone.js`.
```
const delayedPromise = new Promise((resolve) => {
  setTimeout(resolve, 1, 'timeout');
});

new Promise((resolve) => {
  resolve(delayedPromise);
  resolve('second call');
}).then(console.log);
```

It should output `timeout`, since the promise is resolved by the
1st resolve, the `second call` should be ignored.

So this is a bug that the original implementation not ensure the
`resolve` is only called once.

PR Close #45283
2022-03-25 17:31:04 -07:00
Paul Gschwendtner 0c28997739 build: disable payload size uploading within bazel (#45446)
Uploading payload size is unreliable from within Bazel. This is
because tests might not run for every commit, tests might have
been cached from a pull request RBE-build (causing payload uploading
to be skipped most of the time as every change comes from a PR)

We should disable the uploading as this is a fundamental problem
(good thing to note now) that we can solve with better payload
size tracking that we want to establish as part of dev-infra.

PR Close #45446
2022-03-25 16:50:10 -07:00
arturovt 0dd532bcd6 fix(zone.js): swallow the error when the element callback is not patchable (#45400)
The `patchCallbacks` is used for patching the `document.registerElement` and
`customElements.define`. We explicitly wrap the patching code into try-catch since
callbacks may be already patched by other web components frameworks (e.g. LWC), and they
make those properties non-writable. This means that patching callback will throw an error
`cannot assign to read-only property`. See this code as an example:
https://github.com/salesforce/lwc/blob/master/packages/@lwc/engine-core/src/framework/base-bridge-element.ts#L180-L186
We don't want to stop the application rendering if we couldn't patch some
callback, e.g. `attributeChangedCallback`.

PR Close #42546

PR Close #45400
2022-03-25 16:31:10 -07:00
Paul Gschwendtner 8d7fd91a67 ci: make payload size tracking script work with CircleCI and Bazel limitation (#45444)
For quite some time now, since we started to use Bazel for integration tests, we
relied on some size tracking logic that did not actually fully work under Bazel.

It was thought that all the necessary CI push/PR information is available to the
Bazel test, but that was not the case. This was now fixed with the recent Rules NodeJS
v5 update where I made sure the `env.sh` variables are actually available before we
write them to the temporary file for the Bazel-access.

This now will unveil an issue because payload size goldens would start being based
on their branch name. e.g. the golden key in `13.3.x` should not be `master` but
`13.3.x`. This makes more sense than `master` as key, but makes things more
cumbersome and ideally we would not store the branch name at all (this is a larger
change though -- not worth now since we might refactor this anyway). For now we will
update the size tracking logic to always use `master` as golden key (like it worked
in the past year(s))

With the environment fix we now (again) start uploading payload size results to Firebase.
This did not work by accident either. The uploading logic is reliant on the CircleCI
commit range which is not working/reliable in upstream branches. This commit
removes this reliance on `COMMIT_RANGE` since it's not strictly necessary and
currently breaking renovate PRs. We can re-enable this when we have a solution with
CircleCI, or a workaround/resolution logic provided in e.g. `ng-dev ci determine-commit-range`.

PR Close #45444
2022-03-25 14:25:04 -07:00
Paul Gschwendtner 88dbeda931 build: shorten partial compilation test case target names for windows (#45443)
Shortens the partial compilation test case target names as the paths/
manifest paths in Bazel became too large, exceeding some Windows path
length limits.

Relevant context/resources:
* https://angular-team.slack.com/archives/C02PARQNMC1/p1648137933069659 (internal)
* https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd
* https://github.com/bazelbuild/rules_nodejs/pull/3215/files#r782271592

PR Close #45443
2022-03-25 13:45:08 -07:00
Paul Gschwendtner a15c7e8f98 ci: improve stability of windows bazel CI job (#45443)
Improves stability of the Windows Bazel CI job by
installing Bazelisk globally.

Also makes the environment helpers more convenient by
evaluating the variable assignments directly, simplifying
some Bash logic.

PR Close #45443
2022-03-25 13:45:08 -07:00
Paul Gschwendtner 5ab0ca53b6 ci: dedupe top-level yarn install in circleci config (#45443)
Dedupes the Yarn run steps, avoiding the need to manually keep
this step in sync (e.g. with the timeout -- which is currently missing
for the windows job)

PR Close #45443
2022-03-25 13:45:07 -07:00
Paul Gschwendtner c24ea4b4f5 test: refactor compiler-cli compliance test to work on windows (#45443)
Recent changes in `rules_nodejs` caused the test case copy file actions
to be transitioned into the `exec` configuration, resulting in much larger
file paths. These paths break on Windows with the shell argument limit, and
with the path limit, causing errors like:

```
ERROR: C:/users/circleci/ng/packages/compiler-cli/test/compliance/test_cases/BUILD.bazel:9:12: Copying file packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/value_composition/structural_directives_if_directive_def.js failed: (Exit 1): cmd.exe failed: error executing command
  cd /d C:/users/circleci/_bazel_circleci/u4uoan2j/execroot/angular
  SET PATH=C:\Program Files\Git\usr\bin;C:\Program Files\Git\bin;C:\Windows;C:\Windows\System32;C:\Windows\System32\WindowsPowerShell\v1.0
    SET RUNFILES_MANIFEST_ONLY=1
  cmd.exe /C bazel-out\x64_windows-opt-exec-2B5CBBC6\bin\packages\compiler-cli\test\compliance\test_cases\test_cases--1973427149-cmd.bat
The system cannot find the path specified
```

https://app.circleci.com/pipelines/github/angular/angular/44038/workflows/4b530cb2-f232-4e1d-b35a-e6e085151d08/jobs/1140017

PR Close #45443
2022-03-25 13:45:07 -07:00
Paul Gschwendtner c3b3b73e56 ci: make windows circleci job more robust and use git bash (#45443)
It is totally fine, and expected to use Git Bash for running Bazel
on Windows. In fact this is the most common setup for Bazel on Windows
and it's unrealistic to run without it.

This allows us to remove the old/legacy Powershell setup from CI
which is also quite flaky sometimes and does not reproduce how
Bazel is used on windows-users dev machines.

PR Close #45443
2022-03-25 13:45:07 -07:00
Paul Gschwendtner b73d5aebe0 ci: temporarily disable components-repo-unit-tests job for Bazel NodeJS v5 update (#45443)
The Angular components repository can only start using Bazel Rules NodeJS v5
when `@angular/bazel` is published with support for it. To work around this
cycle we temporarily disable the unit tests job until we migrated the COMP
repo as well.

PR Close #45443
2022-03-25 13:45:07 -07:00
Paul Gschwendtner 3f5e685ca9 refactor: remove unused variables in starlark code to satisfy buildifier (#45443)
We updated buildifier and a few warnings became errors now. This commit
cleans up the failing unused variable instances, making the linter happy.

Additionally for the API extractor BUILD file, the package defaults
need to move to satisfy buildifier.

PR Close #45443
2022-03-25 13:45:07 -07:00
Paul Gschwendtner 69e4c9813e build: migrate more usages from @bazel/typescript to @bazel/concatjs (#45443)
As mentioned in previous commits (check them for more details), `@bazel/typescript`
no longer contains `ts_library`-specific code, so we no longer need that dependency.

PR Close #45443
2022-03-25 13:45:07 -07:00
Paul Gschwendtner 1eaaa5d1cc refactor(bazel): update api-extractor to account for @bazel/typescript change (#45443)
`@bazel/typescript` code moved to `@bazel/concatjs` for the tsc-wrapped code.

Note that this code is likely going to be removed anyway soon when we
move dts bundling from `ng_module` to `ng_package`.

PR Close #45443
2022-03-25 13:45:07 -07:00
Paul Gschwendtner 97e3b00e5b build: add temporary patch to make tsec compatible with rules_nodejs v5 (#45443)
Adds a temporary patch to make `tsec` compatible with `rules_nodejs` v5
until https://github.com/google/tsec/pull/25 is available/released.

PR Close #45443
2022-03-25 13:45:07 -07:00
Paul Gschwendtner 1a149bb50d refactor(bazel): update ngc-wrapped to account for tsc-wrapped move to @bazel/concatjs (#45443)
Previously `tsc-wrapped` which is the foundation for `ngc-wrapped`, resided
in `@bazel/typescript`. It has been moved to `@bazel/concatjs` in rules_nodejs
so we need to account for that as part of our rules_nodejs v5 update.

PR Close #45443
2022-03-25 13:45:07 -07:00
Renovate Bot 29d4b78ada build: update bazel (#45443)
Update `@bazel` packages to the latest 5.x version.

Some of the changes here are modeled after
angular/dev-infra@40c0ac8559.

Co-Authored-By: George Kalpakas <kalpakas.g@gmail.com>

PR Close #45443
2022-03-25 13:45:06 -07:00
Renovate Bot 2e79d09d85 build: update angular to 5a82e60 (#45443)
Update the `@angular/dev-infra-private` package to the latest commit.

PR Close #45443
2022-03-25 13:45:06 -07:00
arturovt dbd6be829f fix(zone.js): read Symbol.species safely (#45369)
We must read `Symbol.species` safely because `this` may be anything. For instance, `this`
may be an object without a prototype (created through `Object.create(null)`); thus
`this.constructor` will be undefined. One of the use cases is SystemJS creating
prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty
object and copies promise properties into that object (within the `getOrCreateLoad`
function). The zone.js then checks if the resolved value has the `then` method and invokes
it with the `value` context. Otherwise, this will throw an error: `TypeError: Cannot read
properties of undefined (reading 'Symbol(Symbol.species)')`.

PR Close #45369
2022-03-24 18:56:37 -07:00
khai f869b9146a docs: update for 2022 angular events (#45386)
PR Close #45386
2022-03-24 14:29:50 -07:00
George Kalpakas 1a05e2dc48 build(docs-infra): upgrade cli command docs sources to 15ff62d4d (#45348)
Updating [angular#13.3.x](https://github.com/angular/angular/tree/13.3.x) from
[cli-builds#13.3.x](https://github.com/angular/cli-builds/tree/13.3.x).

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/0f51d5c70...15ff62d4d):

**Modified**
- help/build.json
- help/generate.json
- help/serve.json
- help/test.json

PR Close #45348
2022-03-24 14:24:09 -07:00
mgechev aa29fc7b5c docs: update the public roadmap (#45415)
Change status of existing projects and add new projects we're working
on.

PR Close #45415
2022-03-24 11:29:30 -07:00
George Kalpakas b481eab39d fix(docs-infra): update (and unpin) dependency versions for preview server (#45390)
Update the `Dockerfile` used to create the preview server to use the
latest stable version of Debian (`bullseye`) and also update package
versions to latest versions.

Also, unpin the versions of installed packages (except for Node.js
related ones) as pinning proved problematic due to many packages
removing old versions from the official repositories.

NOTE:
This change will allow the preview server to be updated on the VM and
take advantage of recent fixes, such as #45349. Currently, the update
fails with the error:
```
E: Version '7.64.0-4+deb10u1' for 'curl' was not found
The command '/bin/sh -c apt-get update -y && apt-get install -y curl=7.64.0-4+deb10u1' returned a non-zero code: 100
```

PR Close #45390
2022-03-24 10:53:59 -07:00
arturovt 2b0da62937 fix(zone.js): check if process is defined when patching the GlobalErrors.install (#45392)
Jasmine checks internally if `process` and `process.on` is defined. Otherwise,
it installs the browser rejection handler through the `global.addEventListener`.
This code may be run in the browser environment where `process` is not defined, and
this will lead to a runtime exception since Webpack 5 removed automatic Node.js polyfills.

PR Close #42260

PR Close #45392
2022-03-24 10:52:35 -07:00
Paul Gschwendtner 960e42b2ac fix(bazel): ng module compilation workers are subject to linker race-conditions (#45393)
The Bazel NodeJS rules provide two ways of accessing node modules:

* A linker which creates a `node_modules` directory in the execroot/or in the runfiles.
* A patched module resolution where no node modules directory necessarily needs to exist.

The first is the default in `rules_nodejs` and the second is technically the most idiomatic
resolution mechanism in Bazel (as it matches with a runfile resolution library).

The linker is prone to race conditions in persistent workers, or non-sandbox environments (like
windows). This is because the linker for all workers will operate on a shared `execroot` directory
and the same `node_modules` directory is modified all the time / potentially conflicting with other
linker processes from other concurrently-running workers.

We rely on the patched module resolution anyway, but just need to disable the unused linker to avoid
issues like the following:

```
---8<---8<--- Start of log, file at /private/var/tmp/_bazel_splaktar/280f06d55552a0d01f89f0955b5acd78/bazel-workers/worker-8-TypeScriptCompile.log ---8<---8<---
[link_node_modules.js] An error has been reported: [Error: ENOENT: no such file or directory, unlink 'node_modules'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'unlink',
  path: 'node_modules'
} Error: ENOENT: no such file or directory, unlink 'node_modules'
---8<---8<--- End of log ---8<---8<---
INFO: Elapsed time: 12.796s, Critical Path: 5.39s
INFO: 645 processes: 477 internal, 12 darwin-sandbox, 156 worker.
```

PR Close #45393
2022-03-24 10:52:13 -07:00
Mike cc90fd55b2 docs(router): Fix typo on segments (#45411)
PR Close #45411
2022-03-24 10:49:36 -07:00
Joey Perrott 1734d1e07e fix(docs-infra): prevent framing of AIO with X-Frame-Options (#45419)
Prevent the docs site from being place in an iframe.

PR Close #45419
2022-03-23 12:20:49 -07:00
Ben Brook ee20410a98 docs(docs-infra): fix TypeScript casing (#45307)
PR Close #45307
2022-03-21 16:57:12 -07:00
Paul Gschwendtner 4321e4cdec build: update to bazel v5 for new runfiles API used in dev-infra (#45407)
https://blog.bazel.build/2022/01/19/bazel-5.0.html#starlark-build-language

PR Close #45407
2022-03-21 16:55:37 -07:00
JoostK 3714305f84 fix(compiler): scope css rules within @layer blocks (#45396)
This commit starts scoping CSS rules nested within `@layer` blocks.

Fixes #45389

PR Close #45396
2022-03-21 14:51:46 -07:00
Joey Perrott e5300d6d75 build(docs-infra): move to circleci v2 api for aio-builds (#45349)
Move to the CircleCI v2 api as the authentication fails for downloading artifacts using the v1 methods.

CircleCI v2 api now requires authentication to occur view the headers instead of being done in a
query parameter, all of the CircleCI interactions are now performed through one fetchFromCircleCi method
which ensures the token is provided in the headers as expected.

PR Close #45349
2022-03-17 14:03:27 -07:00
Andrew Scott 3700323e1c docs: changelog for v13.3.0 release (#45367)
PR Close #45367
2022-03-16 12:54:47 -07:00
Andrew Scott 1398acd90c docs: Revert changelog changes from "release: cut the v13.3.0 release (#45365)" (#45367)
This reverts commit CHANGELOG changes from f00f8c4863.

PR Close #45367
2022-03-16 12:54:47 -07:00
Andrew Scott f00f8c4863 release: cut the v13.3.0 release (#45365) 2022-03-16 12:07:42 -07:00
why520crazy 3148ab93a9 docs: add ngx-gantt to "EXPLORE ANGULAR RESOURCES" page (#45351)
PR Close #45351
2022-03-15 16:29:24 -07:00
Amer Yousuf 7ff4c0bf39 fix(forms): improve error message for invalid value accessors (#45192)
improve error message for invalid value accessors when accessor is not provided as array

PR Close #45192
2022-03-15 13:26:04 -07:00
Lee Cooper 2d51587f36 fix(docs-infra): fix tour of heroes global styles (#45329)
fix button styles in src/styles.css that are missing from code snippets

PR Close #45329
2022-03-15 13:24:53 -07:00
alirezaghey bb9b33053c docs: fix small English typo (#45340)
PR Close #45340
2022-03-14 13:10:20 -07:00
Andrew Scott 7eddf582a1 docs: Fix typo in issue template (#45327)
PR Close #45327
2022-03-14 09:31:02 -07:00
Paul Gschwendtner 2a437616bb ci: update payload size goldens to reflect zone.js update (#45298)
ZoneJS has been updated as part of the lock file refresh by Renovate. The
polyfills bundle reduced in size by around 4k which is due to some code
simplication in ZoneJS being finally released. This is the commit responsible
for the major reduction (also mentioning the reduction):

https://github.com/angular/angular/commit/0f298a13dbd141e5440d1388b124d03384641efe

PR Close #45298
2022-03-14 09:29:12 -07:00
Renovate Bot 956b022254 build: lock file maintenance (#45298)
Refreshes the lock file through Renovate.

PR Close #45298
2022-03-14 09:29:12 -07:00
Jessica Janiuk b839aeb2c1 refactor(core): Switch over to new closure LOCALE vs getLocale() (#45302)
This is a change requested via an LSC due to a deprecation.

PR Close #45302
2022-03-10 12:48:30 -08:00
Andrew Scott 0f8e748b07 release: cut the v13.3.0-rc.0 release (#45321) 2022-03-10 11:14:48 -08:00
Kristiyan Kostadinov 895c5417e3 Set up 13.3.0 release for TypeScript 4.6 support (#45319)
* feat(core): support TypeScript 4.6 (#45190)

Adds support for TypeScript 4.6.

PR Close #45190

* build: update version to 13.3.0

Bumps up the version to 13.3.0-next.0 so the tooling can pick it up.
2022-03-10 10:33:21 -08:00
Andrew Scott 6336b8e5b3 refactor(router): Make a few adjustments to createUrlTree for clarity (#45306)
* `tree` function now accepts the old root rather than the old
  `UrlTree`. The `urlTree` argument was only used to get the `root`.
  This change makes it more clear what that pararmeter is used for and
  what's actually being used
* Move the `oldRoot` (previously `urlTree`) to be the first argument of `tree`.
  This change now mirrors the argument order for `replaceSegment` and
  can be read from left to right more easily "in this root,
  replace this old segment group with this new segment group".
* Extract `newRoot` to a variable. This just makes it more clear what's
  going on at the end rather than combining a bunch of operations into
  one.

These changes are being made so that hopefully a future refactor can be
done which does not rely on the `urlTree` argument at all in the
`createUrlTree` function. These refactorings will make it easier to see
1:1 functionlity in these various places.

PR Close #45306
2022-03-09 13:52:38 -08:00
Alistair Kane 10de52887b docs: update <div> to <p> in lifecycle-hooks.md (#45063)
Changes <div> to <p> in description to match the elements in the screenshot.

Update lifecycle-hooks.md

Changes <div> to <p> in description to match the elements in the screenshot.

PR Close #45063
2022-03-09 13:52:16 -08:00
Andrew Kushnir 6f1c941dfe release: cut the v13.2.6 release (#45299) 2022-03-09 08:53:23 -08:00
Andrew Scott 9bce9ce89e fix(language-service): Prioritize Angular-specific completions over DOM completions (#45293)
When authoring Angular templates, developers are likely to be most interested in
the current Directive/Component inputs and outputs, then potential
attributes which would match other directives to the element,
and lastly the plethora of DOM events and attributes.

This change ensures that Angular-specific information appears above DOM
information by prepending the first printable ASCII characters to the
sort text.

Fixes https://github.com/angular/vscode-ng-language-service/issues/1537

PR Close #45293
2022-03-08 14:48:38 -08:00
Andrew Scott 8227eb914e refactor(migrations): update isReferenceToImport to not use valueDeclaration (#45292)
valueDeclaration is only set when the Symbol type is a `Value`:

* [setValueDeclaration](https://sourcegraph.com/github.com/microsoft/TypeScript@d8b21a8d6cef772fea5cf2a507b651c5d38194bd/-/blob/src/compiler/binder.ts?L321-322)
* [Value union](https://sourcegraph.com/github.com/microsoft/TypeScript@d8b21a8d6cef772fea5cf2a507b651c5d38194bd/-/blob/src/compiler/types.ts?L4849:9#tab=references)

This won't be the case if the symbol is an interface (notice that `Interface` is not in the union for `Value` above).

For this reason, we can't rely on the `valueDeclaration` property of the symbol.
Instead, it's more reliable to just compare the first items in the `declarations` list.

PR Close #45292
2022-03-08 13:13:26 -08:00
Renovate Bot 23003f817f build: update actions/checkout action to v3 (#45248)
PR Close #45248
2022-03-08 10:28:32 -08:00
Mladen Jakovljević d98ce5ed4f fix(docs-infra): remove anchor tags from heritage docs (#45287)
Remove anchor tags from heritage docs and let `autoLinkCode` insert them properly.

PR Close #45287
2022-03-08 10:26:50 -08:00
Luca cff1c5622f fix(service-worker): file system hash in batch of 500 elements (#45262)
Add file system concurrency hash test

Fixes #45133
PR Close #45262
2022-03-08 10:23:39 -08:00
Andrew Scott 6efa366e2c fix(compiler): compute correct offsets when interpolations have HTML entities (#44811)
When parsing interpolations, the input string is _decoded_ from what was
in the orginal template. This means that we cannot soley rely on the input
string to compute source spans because it does not necessarily reflect
the exact content of the original template. Specifically, when there is
an HTML entity (i.e. `&nbsp;`), this will show up in its decoded form
when processing the interpolation (' '). We need to compute offsets
using the original _encoded_ string.

Note that this problem only surfaces in the splitting of interpolations.
The spans to this point have already been tracked accurately. For
example, given the template `&nbsp;<div></div>`, the source span for the
`div` is already correctly determined to be 6. Only when we encounter
interpolations with many parts do we run into situations where we need
to compute new spans for the individual parts of the interpolation.

PR Close #44811
2022-03-08 10:23:08 -08:00
Srikanth Kolli ad9d98146e docs: Change tag name to TD from TR in context of colspan usage (#45257)
PR Close #45257
2022-03-07 15:41:37 -08:00
nanda18 8390e12bdd docs: update flush description to include microtasks (#45237)
PR Close #45237
2022-03-07 15:41:08 -08:00
Renovate Bot 43bbaf810d build: update dependency google-closure-compiler to v20220301 (#45260)
PR Close #45260
2022-03-07 14:30:47 -08:00
Renovate Bot 6842bf0515 build: update dependency magic-string to v0.26.1 (#45247)
PR Close #45247
2022-03-07 14:29:46 -08:00
Kristiyan Kostadinov f261fa7c08 test(compiler): fix deprecation warning (#45285)
Jasmine logs a warning when there's a `describe` with no tests. These changes fix one such case in the compiler that happens when the tests are run against Windows.

PR Close #45285
2022-03-07 11:36:48 -08:00
JiaLiPassion d29883adff ci: components CI test should use local zone.js build (#45277)
CI components test install the angular package from the local
version, but still use the zone.js from npm, so this commit let
components also install zone.js from local too.

PR Close #45277
2022-03-07 11:35:00 -08:00
Andrew Scott de67c9fd01 refactor(router): Use helper function to throw NoMatch (#45244)
This update matches the other locations where noMatch is thrown.

PR Close #45244
2022-03-04 15:24:14 -08:00
Joey Perrott 9a8ef7cc28 build: patch snapshot issue in dev-infra selecting the latest version tag (#45269)
Local patch ahead of landing of https://github.com/angular/dev-infra/pull/449

PR Close #45269
2022-03-04 15:23:40 -08:00
Anner Visser 4e1d825d83 docs: change link for devtools to angular repo (#45207)
PR Close #45207
2022-03-03 12:28:25 -08:00
Aristeidis Bampakos 356c521195 docs: add Greek localization for Angular Docs (#45152)
PR Close #45152
2022-03-03 12:27:53 -08:00
JiaLiPassion 9a7eba2352 fix(zone.js): defineProperties should also set symbol props (#45098)
Close #44095

Fix `defineProperties` patch not set `symbol` props issue.

Co-authored-by: varomodt<varomodt@users.noreply.github.com>
Co-authored-by: AndrewKushnir<AndrewKushnir@users.noreply.github.com>

PR Close #45098
2022-03-03 12:22:05 -08:00
Andrew Scott e16dab82a1 refactor(router): Remove special logic for hybrid apps (#45240)
This commit removes special (undocumented) logic in the Router code that is
meant to prevent duplicate navigations that result from location syncs in
AngularJS/Angular hybrid applications.

The duplicate navigations can occur when both the Router and the AngularJS sync
code detect a location change via a popstate/hashchange event. When this
happens, the Angular Router schedules a navigation to sync itself with
the browser, but the hybrid listener may also schedule an additional
navigation. There are a few reasons this logic should not be included in
the Router:

* This special logic is not tree shakeable so it introduces a bundle
  size cost for all applications, most of which don't need it.
* There have been many updates to the routing pipeline to tolerate
  duplicate navigations. That is, duplicate navigations can happen and
  routing should still complete successfully.
    * https://github.com/angular/angular/commit/0e8548f667e5fdefa3ac7cdf1ba47e3e17011ffc
    * https://github.com/angular/angular/commit/9e039ca68bfae5328f3fc1f16fabd7673c466a25
* The logic is really in the wrong place: The hybrid sync code should be
  the location to handle this. If duplicate navigations are meant to be
  avoided, the hybrid sync code should have handling to _not_ trigger
  duplicate navs.
* This logic _also_ used to exist because the mock location
  helper used for test incorrectly triggered popstate events during
  router navigations. In order to avoid unexpected behavior in tests, this
  logic needed to be added. This incorrect mocking may also have been
  put in place because the upgrade module _would_ see a location change
  event and trigger a duplicate navigation.  The location mock has since been updated to
  match real browser behavior so this is no longer necessary. The
  upgrade module has also been updated to not trigger duplicate
  navigations.  The following commits are related to this:
    * https://github.com/angular/angular/commit/202a1a56314af4ddb99c476f974536a10e390319
    * https://github.com/angular/angular/commit/c6a93001eb74374b0fbc6aea1286fe1183d21382

Side note: The `setTimeout` in the location change listener is used to
ensure the ordering of duplicate navigations was consistent. You can see
that the logic being removed here expects the imperative navigation to precede the
popstate/hashchange. With the removal of this code, the `setTimeout` no
longer serves a purpose. However, it has been found that tests can rely
on this behavior (incorrectly) because they expect the navigation to be
complete but in reality, it hasn't even started because the test has not
flushed the timeout. Removing the timeout would be a breaking change as
a result.

PR Close #45240
2022-03-03 09:14:39 -08:00
Paul Gschwendtner 913bbba42b ci: update aio payload size golden to reflect Angular update (#45239)
Similar to 63e9cc7cba, but for the
patch branch where the `aio` job increased in total by ~100b.

New total: 718427 bytes
Before total: 718357 bytes

PR Close #45239
2022-03-03 09:14:08 -08:00
Joey Perrott c7e5cb0371 build: update .pullapprove.yml (#45061) (#45239)
Remove errant extra space in fw-compiler glob matcher.

PR Close #45061

PR Close #45239
2022-03-03 09:14:08 -08:00
Paul Gschwendtner aa616db24f build: update tooling to use new entry-point for dev-infra exports (#45239)
Previously, dev-infra only bundled the CLI with all its dependencies, while
we still also kept all bundled dependencies in the `dependencies`. This basically
meant that the CLI bundling did not provide any value at all.

We fixed this upstream and now dependencies are still bundled, but no longer
also declared as `dependencies`. We also stopped shipping deep JS files, only
shipping the bundles now.

As part of this deep file removal, we introduced a runtime entry-point for
exports/types. This one will also benefit from the bundling and it will be
predictable what symbols dev-infra consumer projects rely on (allowing us to
also have an API guard or something in the future).

PR Close #45239
2022-03-03 09:14:08 -08:00
Renovate Bot de9290096c build: update angular (#45239)
Updates Angular through Renovate. Patch port.

PR Close #45239
2022-03-03 09:14:08 -08:00
Kristiyan Kostadinov 2c7d96afcb build: add retry logic to postinstall script (#45252)
Several people on the team (myself included) have had issues where the `webdriver-manager` step of the `postinstall` script fails on the first run, but work correctly on the second one.

These changes attempt to simplify the workflow by retrying the script up to 3 times before giving up.

PR Close #45252
2022-03-03 09:13:26 -08:00
Jessica Janiuk 8bf3b53a1d release: cut the v13.2.5 release (#45241) 2022-03-02 10:18:07 -08:00
Andrew Kushnir 56ca7d385b perf(common): make NgLocalization token tree-shakable (#45118) (#45226)
This commit updates the `NgLocalization` token to become tree-shakable (vs using a direct reference to that token in the `providers` section of the `CommonModule`). The `NgLocalization` token is used for apps that use i18n and for other apps it would be excluded from the bundle.

PR Close #45118

PR Close #45226
2022-03-02 01:02:54 +00:00
Theodore Brown e8fd452bd2 fix(core): remove individual commands for updating gold files (#45198)
The documented command for updating the forms gold files was outdated
and didn't work. Since this command list can easily become outdated,
remove the individual commands in favor of the simpler global scripts.

PR Close #45198
2022-03-01 19:16:53 +00:00
Andrew Kushnir 71ff12c1cc perf(core): make LOCALE_ID and other tokens from ApplicationModule tree-shakable (#45102) (#45222)
The `ApplicationModule` module has a number of tokens declared as non-tree-shakable providers. This commit updates them to make tree-shakable.

PR Close #45102

PR Close #45222
2022-03-01 18:38:18 +00:00
Andrew Kushnir 82d772857c perf(core): make Compiler, ApplicationRef and ApplicationInitStatus tree-shakable (#45102) (#45222)
The `Compiler`, `ApplicationRef` and `ApplicationInitStatus` classes are registered as non-tree-shakable providers in the `ApplicationModule`. This commit converts them to the tree-shakable providers instead.

PR Close #45102

PR Close #45222
2022-03-01 18:38:17 +00:00
Andrew Kushnir 2bebaa99cf refactor(core): drop unused SCHEDULER provider (#45102) (#45222)
The `SCHEDULER` provider was used previously when both ViewEngine and Ivy code was present. After some prior refactoring, all references to the `SCHEDULER` token were removed, but the token itself remains present in the `ApplicationModule`, which makes it non-tree-shakable.

This commit removes the `SCHEDULER` token as unused.

PR Close #45102

PR Close #45222
2022-03-01 18:38:17 +00:00
dario-piotrowicz 8907fbbfed docs: improve structure of http example (#44986)
improve the http aio example by:
 - adding a background color to the messages section so that it
   can be distinguished from the others
 - avoid using `hr` elements to divide the various sections, use
   css instead (so that the divisions can also be omitted when
   the sections are not being shown)
 - fix the erroneous presence of an input text element inside a button
   (see: https://github.com/angular/angular/pull/44557#discussion_r787239658)

PR Close #44986
2022-02-28 19:31:25 +00:00
Guillaume Bonnet 84b4ad812b docs(docs-infra): fix the stackblitz on page i18n-example (#45097)
The previous configuration didn't allow to serve in any language.

Fixes #45066

PR Close #45097
2022-02-28 17:25:41 +00:00
Paul Gschwendtner 76c6dca93f ci: instruct renovate to not update/override merge ready PRs (#45204)
Sometimes Renovate proposes an update and we need to add some
manual fixups, like updating a size golden. For this we push to
same upstream branch.

Renovate will update the PR though when another new revision/version
becomes available, overriding the fixup and discarding it.

This happened quite often now and causes significantly more
work required by the dev-infra time..

PR Close #45204
2022-02-25 22:10:55 +00:00
Paul Gschwendtner 85546594a5 ci: fix stamping for builds performed in CI (#45147)
Fixes the stamping for snapshot builds and the artifact deployment job.
Currently the stamped versions will have the `.with-local-changes` version
suffix given that we add a file to the Git repo that is just
needed for the CircleCI cache key computation.

PR Close #45147
2022-02-25 19:14:05 +00:00
JoostK 55b8c4f701 ci: allow Babel to be updated by Renovate (#45203)
Automatic updating of Babel was disabled because there were build failures
when using the latest version of Babel, but these have been resolved in
#44931. This commit removes Babel packages from Renovate's ignored list
to allow automatic updates again.

PR Close #45203
2022-02-25 19:13:23 +00:00
JoostK 1e6f700b7d refactor(localize): update version of Babel (#45203)
The `@angular/localize` package depends on a version of Babel that is two years
old, so this commit updates to the latest version.

Some changes were made to the linker and compliance tests to account for slight
changes in source maps, along with a few code updates because of changes to
the typings of Babel.

PR Close #45203
2022-02-25 19:13:23 +00:00
Andrew Scott 01fde59dd9 refactor(router): Refactor errors in applyRedirects to use common throwError function (#45170)
The implementation of `throwError` in `rxjs` is identical to what is
done manually in the Router code.

PR Close #45170
2022-02-24 23:50:01 +00:00
Andrew Scott a4debf14e3 refactor(router): Update match result to be more explicit (#45170)
The `lastChild` property in the match result is only used to compute the
remaining segments (i.e. the ones which were not consumed). The updated
type here makes it easier to use and more clear.

PR Close #45170
2022-02-24 23:50:01 +00:00
dario-piotrowicz c6e64aa8ad docs: fix style guide example app included as routing (#45148)
in the aio example apps page the style guide for documentation
contributions is included in the Routing section instead of being
in its own section, add a documentation section and include the example
in that one

PR Close #45148
2022-02-24 22:57:54 +00:00
Charles Lyding 7379d75782 ci: add permissions to current github action workflows (#45177)
The currently recommended best practice for Github action workflows is to set top-level permissions to read only. And if the job uses the automatic `GITHUB_TOKEN`, fine-grained permissions for each job based on the job's requirements should also be added.
All existing workflows in the repository now have top-level read only permission blocks.
Only the `scorecard` workflow currently requires additional job level permissions and the minimum set of permissions were already present for the job.

PR Close #45177
2022-02-24 21:39:38 +00:00
Jessica Janiuk 21a51fb6a4 test(animations): Fix flaky animations e2e test (#45196)
This adds a 300ms wait to the animations tests to ensure they are fully done animating before asserting.

PR Close #45196
2022-02-24 13:15:33 -08:00
dario-piotrowicz b39db80f91 test(animations): add route animation delay to pages tests (#45144)
PR #44550 introduced an animation for pages/tabs transitions in the
animations example application, after such change intermittent e2e
failures started to occur (see for example: #45083), add a delay to
account for such animation to all the animations pages/tabs e2e tests so
to fix the flakyness caused by the animation

PR Close #45144
2022-02-24 18:41:56 +00:00
Martin Sikora 3b86dda068 refactor(http): change <script>'s ownerDocument in jsonp teardown (#36807)
handler

Cancel pending json handler by adopting its <script> element into
another document
(https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-block)
This way the browser will prevent the script from being parsed and executed.

Fixes #34818

PR Close #36807
2022-02-24 17:24:34 +00:00
Martin Sikora 64da1daa78 fix(common): canceled JSONP requests won't throw console error with missing callback function (#36807)
This commit fixes a use-case where unsubscribing from a JSONP request will result in "Uncaught ReferenceError: ng_jsonp_callback_xy is not defined"
thrown into console. Unsubscribing won't remove its associated callback function because the requested script will finish
loading anyway and will try to call the handler.

PR Close #34818

PR Close #36807
2022-02-24 17:24:34 +00:00
JoostK d388522745 fix(localize): avoid imports into compiler-cli package (#45180)
The compiler-cli's declaration files are not necessarily compatible with web
environments that use `@angular/localize`, and would inadvertently include
`typescript` declaration files in any compilation unit that uses
`@angular/localize` (which increases parsing time and memory usage during
builds) using a default import that only type-checks when
`allowSyntheticDefaultImports` is enabled.

Fixes #45179

PR Close #45180
2022-02-24 17:12:10 +00:00
dario-piotrowicz 4f1870362e docs: remove activatedRouteData backward accesses in aio guides (#45140)
developers should not access the router-outlet directive in their
template before defining a template variable for it, such
implementation is present in a couple of aio guides, fix such guides
so that they show the more correct way of accessing the outlet's data

resolves #36173

PR Close #45140
2022-02-24 00:55:19 +00:00
ivanwonder 6c906a5bb9 fix(compiler-cli): Support resolve animation name from the DTS (#45169)
Before this, the compiler resolves the value in the DTS as dynamic.
If the `trigger` is imported from `@angular/animations`, this PR will
use FFR to simulate the actual implementation in JS and extracts the
animation name.

PR Close #45169
2022-02-24 00:54:33 +00:00
dario-piotrowicz 6c61d20476 fix(animations): allow animations with unsupported CSS properties (#45185)
currently animations with unsupported CSS properties cause a hard error
and the crash of the animation itself, instead of this behaviour just
ignore such properties and provide a warning for the developer in
the console (only in dev mode)

this change also introduces a general way to present warnings
in the animations code

resolves #23195

PR Close #45185
2022-02-24 00:53:50 +00:00
Andrew Scott e914da145b release: cut the v13.2.4 release (#45181) 2022-02-23 12:35:31 -08:00
Alan Cohen 6550c59df5 docs: fix test description to match code example (#45101)
PR Close #45101
2022-02-23 08:58:41 -08:00
Daniele Maltese 032276253f fix(docs-infra): removed duplicated style in aio examples (#45157)
Removed duplicated style in aio example scss files.

PR Close #45157
2022-02-22 15:35:17 -08:00
Renovate Bot d607d0b93c build: update ossf/scorecard-action commit hash to 3662744 (#45162)
PR Close #45162
2022-02-22 12:48:12 -08:00
Paul Gschwendtner c02e4d72bc ci: update SHA for components-repo-unit-tests job to fix flakiness (#45166)
This commit attemps to fix the flakiness that shows up sometimes
in the `components-repo-unit-tests` job. See:

https://app.circleci.com/pipelines/github/angular/angular/43024/workflows/fa9bc546-179a-4215-a7f1-db123efa0fa4/jobs/1126909

We updated Firefox/Chromium in dev-infra, hoping to fix this non-reproducable
flakiness (also checked memory/CPU consumption in the test). So far it looks like
the update helped in the COMP repo so we should try it here as well.

PR Close #45166
2022-02-22 10:20:32 -08:00
Renovate Bot 4d2ef0f5df build: update scorecard action dependencies to 040feef (#45135)
PR Close #45135
2022-02-18 13:57:04 -08:00
JoostK 1a4b489692 perf(animations): improve algorithm to balance animation namespaces (#45113)
The prior approach would consider all existing namespaces from back to front
to find the one that's the closest ancestor for a given host element. An
expensive `contains` operation was used which needed to traverse all the
way up the document root _for each existing namespace_. This commit implements
an optimization where the closest namespace is found by traversing up from
the host element, avoiding repeated DOM traversal.

Closes #45055

PR Close #45113
2022-02-18 13:44:44 -08:00
Andrew Kushnir cbd23ee0de perf(core): make IterableDiffers and KeyValueDiffers tree-shakable (#45094) (#45115)
This commit removed references to the `IterableDiffers` and `KeyValueDiffers` classes from the `ApplicationModule`, which effectively make them tree-shakable. Both classes have `prov` static field with the right setup, so they'll be properly initialized when referenced.

PR Close #45094

PR Close #45115
2022-02-18 13:43:05 -08:00
manuelkroiss 5d08390584 docs: replace deprecated SwUpdate#available/activated with new API (#44858)
Since `SwUpdate#available` and `SwUpdate#activated` are deprecated, the new way should be included in the docs instead of the deprecated one.

docs: added missing imports

added imports for VersionReadyEvent, filter, and map

docs: updated service-worker-communications.md

rewrite of SwUpdate service to describe the new versionUpdates property

docs: Apply suggestions from code review

Co-authored-by: George Kalpakas <kalpakas.g@gmail.com>

docs: added events

added VERSION_DETECTED and VERSION_INSTALLATION_FAILED

docs: Apply suggestions from code review

Co-authored-by: George Kalpakas <kalpakas.g@gmail.com>

PR Close #44858
2022-02-18 13:40:35 -08:00
dario-piotrowicz 9b1d3d2fce fix(docs-infra): make hamburger menu non focusable when not visible (#45067)
the header hamburger menu gets removed from the page by moving it
outside the screen, it can however still be accessed via keyboard
navigation, add a visibility hidden to the element to prevent such
behavior

PR Close #45067
2022-02-18 13:36:11 -08:00
dario-piotrowicz f71eb58036 docs(animations): remove query call in animations example (#45126)
the query call used for the transition between the Home and About tabs
doesn't work as intented since it doesn't find any matching element,
remove such quering since it is not needed

PR Close #45126
2022-02-18 13:35:23 -08:00
David Wolf f7a2dd88aa docs(forms): remove type duplicate from button in reactive-forms example (#45124)
PR Close #45124
2022-02-18 13:35:00 -08:00
AlirezaEbrahimkhani 031e23b06a docs: solve the problem with Dynamic Component guide example (#45123)
solve ExpressionChangedAfterItHasBeenChecked error by changing the angular lifecycle hook ngAfterViewInit to ngOnInit

resolves angular#44925

PR Close #45123
2022-02-18 13:33:16 -08:00
Alan Cohen 5b0980f050 docs: fix test examples to use withContext (#45100)
PR Close #45100
2022-02-18 13:32:45 -08:00
Alex Rickabaugh 54d09a6bc0 release: cut the v13.2.3 release (#45116)
PR Close #45116
2022-02-16 15:50:24 -08:00
Renovate Bot 782f678236 build: update scorecard action dependencies to c4e058a (#45036)
PR Close #45036
2022-02-16 13:52:24 -08:00
JiaLiPassion 62cec95981 test(zone.js): add integration test for zone.js Mocha patch (#45047)
Add integration test for `Mocha` patch from `zone.js` to verify the
issue #42384 is fixed

PR Close #45047
2022-02-16 13:51:52 -08:00
JiaLiPassion 2ec696a50f fix(zone.js): patch global instead of Mocha object (#45047)
Close #42834

In the new version fo Mocha, all global test functions are from `global`
object instead of `Mocha` object. Adn the current `zone.js` Mocha
patch's logic looks like this.

```
global.describe = Mocha.describe = function() {
  return originalMochaDescribe.apply(this, arguments);
}
```

and `originalMochaDescribe` is the unpathced Mocha implementation
looks like this

```
function describe() {
  return context.describe(...);
}
```

And the `context` will finally delegate to `global.describe()`,
so the current `zone.js` patch causes infinite loop.

This commit will not patch function of `Mocha` object any longer.

PR Close #45047
2022-02-16 13:51:52 -08:00
Aristeidis Bampakos 119fbddb83 docs: clarify install of build schematics deps (#45104)
PR Close #45104
2022-02-16 13:44:47 -08:00
Yousaf Nawaz e8e09d3455 docs: fix typos (#45103)
correct word 'questionaire' to 'questionnaire' in Building dynamic forms guide

PR Close #45103
2022-02-16 13:42:45 -08:00
AlirezaEbrahimkhani d7c20c8886 docs: fix case types guide (#45095)
fix case types guide text for more detailed guidance

PR Close #45095
2022-02-16 13:36:08 -08:00
AlirezaEbrahimkhani 3e1fad406a docs: remove duplicate link (#45095)
The link to complete schema, is exactly the same as the one above

PR Close #45095
2022-02-16 13:36:08 -08:00
zuckjet aeeb1b55d3 docs(localize): fix angular.json syntax error about i18n (#45048)
In chapter internationlization at section "Deploy multiple locales" the
syntax for angular.json is wrong.

Close #45032

PR Close #45048
2022-02-15 12:31:12 -08:00
AlirezaEbrahimkhani 331383b39b docs: fix grammatical error (#45092)
'an' is replaced with 'a' for the adjective 'straightforward'

resolves angular#45075

PR Close #45092
2022-02-15 12:29:59 -08:00
Jessica Janiuk 0050b01b62 perf(animations): made errors in the animations package tree shakeable (#45079)
This moves all the error strings into exported functions that can be tree shaken away.

PR Close #45079
2022-02-14 16:13:36 -08:00
Jessica Janiuk e632fd1f0f test(animations): Fix e2e intermittent failures (#45083)
This addresses a problem with animations e2e tests that were failing intermittently due to a missing timeout value

PR Close #45083
2022-02-14 15:45:41 -08:00
mgechev 128038e486 docs: extend the LTS for ngUpgrade with a year (#45078)
PR Close #45078
2022-02-14 14:06:59 -08:00
dario-piotrowicz 42c8533f42 docs(animations): clarify information about query with :leave (#45059)
add information to the query api docs clarifying that elements with
a trigger can be queried via `:leave` when their parent is leaving

this exception is potentially something to be changed (see #45058)
but for the time being the docs can be updated to make the users
aware of such behavior

PR Close #45059
2022-02-14 14:05:22 -08:00
Mina Hosseini Moghadam 2cc8fb0a08 docs: change dependencies to devDependencies in document (#45053)
after installing @angular/localize package, it will be placed in devDependencies object
PR Close #45053
2022-02-14 14:03:45 -08:00
Patrick Cameron 4013db6fd2 fix(docs-infra): fix broken link in Glossary (#45068)
Fix broken link in Glossary document

PR Close #45068
2022-02-14 12:51:30 -08:00
Dario Piotrowicz 95ee74a66c docs(animations): improve aio animations guides info around :enter/:leave (#44550)
improve the aio animations guide information around elements entering and
leaving, this includes, querying them, their transitions and also improvements
to the animations guide live examples

PR Close #44550
2022-02-14 09:16:30 -08:00
markostanimirovic a782be62e9 refactor(docs-infra): replace deprecated toPromise usages (#45045)
This commit replaces deprecated `Observable.toPromise` usages
with `lastValueFrom`.

PR Close #45045
2022-02-11 14:34:28 -08:00
markostanimirovic dc4115d7ed refactor(docs-infra): replace deprecated subscribe usages (#45046)
This commit replaces deprecated `Observable.subscribe` usages.

PR Close #45046
2022-02-11 14:33:46 -08:00
Renovate Bot d8a18717da build: update angular (#45040)
Update Angular packages to latest versions.

PR Close #45040
2022-02-10 09:16:14 -08:00
Srdjan Milic dd177e2c18 refactor(http): deprecated symbol used (#44985)
Support for passing an error value to "throwError" method will be removed in v8 of rxjs. More info at https://rxjs.dev/api/index/function/throwError#throwerror

PR Close #44985
2022-02-09 11:46:32 -08:00
dario-piotrowicz 0b8208690c docs: improve try-it-now card focus area (#45002)
the focus/interactable area for the try-it-now card is wider than
necessary, reduce such width to the appropriate size

PR Close #45002
2022-02-09 10:23:08 -08:00
Renovate Bot 7af1f0a265 build: update scorecard action dependencies to 7f9dca2 (#45026)
PR Close #45026
2022-02-09 10:21:47 -08:00
Renovate Bot d0b88a6810 build: update angular (#44981) (#45027)
Updates Angular

PR Close #44981

PR Close #45027
2022-02-09 10:18:09 -08:00
Renovate Bot fd860e3ef7 build: lock file maintenance (#45027)
Lock file maintenance, patch port #44993.

PR Close #45027
2022-02-09 10:18:09 -08:00
Renovate Bot a01ae487d7 build: update dependency google-closure-compiler to v20220202 (#45013)
PR Close #45013
2022-02-08 11:16:08 -08:00
Renovate Bot 3769de2caa build: update scorecard action dependencies to 230611d (#45012)
PR Close #45012
2022-02-08 11:15:36 -08:00
Amer Yousuf 835b326759 docs(forms): improve email validator directive docs (#45014)
PR Close #45014
2022-02-08 09:57:58 -08:00
Andrew Kushnir 92cf9fbebe fix(core): ViewContainerRef.createComponent should consult module injector when custom one is provided (#44966)
Before Ivy, it was only possible to call the `ViewContainerRef.createComponent` function with the ComponentFactory as the first argument. An instance of a `ComponentFactory` resolved via `ComponentFactoryResolver` contained a reference to an `NgModule` where the component is declared. As a result, the component maintained a DI connection with the module injector tree (by retrieving an instance of `NgModuleRef` internally), even when the custom injector was provided (we try to find a token in a custom injector first and consult module injector after that).

With Ivy, we expanded the `ViewContainerRef.createComponent` function API to support direct references to the Component classes without going through the factory resolution step. As a result, there was no connection to the NgModule that declares the component. Thus, if you provide a custom injector, this is the only injector that is taken into account.

This commit updates the logic for the factory-less case to try retrieving an instance of an `NgModuleRef` using the DI tree which `ViewContainerRef` belongs to. The `NgModuleRef` instance is then used to get a hold of a module injector tree. This brings the factory-less and factory-based logic to more consistent state.

Closes #44897.

PR Close #44966
2022-02-08 09:57:21 -08:00
Kristiyan Kostadinov 09f0254bdd perf(compiler): chain element start/end instructions (#44994)
In templates with several levels of nested nodes, it's common for several `elementStart`/`elementEnd` instructions to show up in a row which can be optimized away.

These changes add chaining support for `elementStart`, `elementEnd`, `elementContainerStart` and `elementContainerEnd` to shave off some bytes when possible.

PR Close #44994
2022-02-08 09:56:51 -08:00
Kristiyan Kostadinov 7b9490ad64 refactor(compiler): rework instruction generation logic for improved flexibility (#44994)
Previously the logic for generating chained instructions was somewhat rigid, because we had to collect all of the calls ahead of time and then call one of the chained instruction helpers. This doesn't work for something like `elementStart`, because we have to descend into other elements that could add to the chain.

These changes refactor the code so that we collect the list of instructions in a flat array and we do the chaining only once at the end when we have the entire instruction set for the code block.

The new approach has the advantage of being (almost) entirely configuration-based via the `CHAINABLE_INSTRUCTIONS` array and being more flexible in allowing us to chain instructions that span across elements.

PR Close #44994
2022-02-08 09:56:50 -08:00
Esteban Gehring f0e82c8af4 docs(common): mark lifecycle methods as nodoc (#45017)
PR Close #45017
2022-02-08 09:56:29 -08:00
651 changed files with 45525 additions and 37153 deletions
+1 -1
View File
@@ -1 +1 @@
4.2.2
5.0.0
+67 -52
View File
@@ -31,12 +31,12 @@ var_3: &cache_key v6-angular-node-14-{{ checksum "month.txt" }}-{{ checksum ".ba
var_4: &cache_key_fallback v6-angular-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}
# Windows needs its own cache key because binaries in node_modules are different.
var_3_win: &cache_key_win v6-angular-win-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "aio/yarn.lock" }}
var_4_win: &cache_key_win_fallback v6-angular-win-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}
var_3_win: &cache_key_win v7-angular-win-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}
var_4_win: &cache_key_win_fallback v7-angular-win-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}
# Cache key for the `components-repo-unit-tests` job. **Note** when updating the SHA in the
# cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable.
var_5: &components_repo_unit_tests_cache_key v1-angular-components-{{ checksum "month.txt" }}-d1cd928714c2d6e3de75f9469ce58b06aad6353c
var_5: &components_repo_unit_tests_cache_key v1-angular-components-{{ checksum "month.txt" }}-e65f5f5bafcd00dbb64387878fb866283909a2dd
var_6: &components_repo_unit_tests_cache_key_fallback v1-angular-components-{{ checksum "month.txt" }}
# Workspace initially persisted by the `setup` job, and then enhanced by `build-npm-packages`.
@@ -58,11 +58,13 @@ var_9: &skip_on_pull_requests
ignore:
- /pull\/\d+/
# Filter to run a job on builds for the master branch only.
var_10: &only_on_master
# Filter to run a job on builds for the main branch only.
var_10: &only_on_main_branch
filters:
branches:
only:
- main
# TODO(BRANCH_RENAME_CLEANUP): remove
- master
# Filter to run a job on all releasable branches.
@@ -70,9 +72,16 @@ var_11: &only_release_branches
filters:
branches:
only:
- main
# TODO(BRANCH_RENAME_CLEANUP): remove
- master
- /\d+\.\d+\.x/
# CircleCI orbs
# https://circleci.com/developer/orbs.
orbs:
node: circleci/node@5.0.1
# Executor Definitions
# https://circleci.com/docs/2.0/reusing-config/#authoring-reusable-executors
# **NOTE 1**: Pin to exact images using an ID (SHA). See https://circleci.com/docs/2.0/circleci-images/#using-a-docker-image-id-to-pin-an-image-to-a-fixed-version.
@@ -103,20 +112,8 @@ executors:
windows-executor:
working_directory: ~/ng
resource_class: windows.2xlarge
# CircleCI windows VMs do have the GitBash shell available:
# https://github.com/CircleCI-Public/windows-preview-docs#shells
# But in this specific case we really should not use it because Bazel must not be ran from
# GitBash. These issues discuss why:
# https://github.com/bazelbuild/bazel/issues/5751
# https://github.com/bazelbuild/bazel/issues/5724#issuecomment-410194038
# https://github.com/bazelbuild/bazel/issues/6339#issuecomment-441600879
shell: powershell.exe -ExecutionPolicy Bypass
shell: bash
machine:
# Windows preview image that includes the following:
# - Visual Studio 2019 build tools
# - Node 14
# - yarn 1.17
# - Python 3 3.7.4
image: windows-server-2019-vs2019:201908-02
# Command Definitions
@@ -188,30 +185,18 @@ commands:
steps:
- run:
name: Save month to file
# Note: Make sure this file is excluded in the `.gitignore` as otherwise the
# snapshot stamping would have the `-with-local-changes` suffix.
command: date +%Y-%m > month.txt
# Normally this would be an individual job instead of a command.
# But startup and setup time for each individual windows job are high enough to discourage
# many small jobs, so instead we use a command for setup unless the gain becomes significant.
setup_win:
description: Setup windows node environment
yarn_install:
description: Install dependencies
steps:
- checkout
- save_month_to_file
# Install Bazel pre-requisites that aren't in the preconfigured CircleCI Windows VM.
- run: ./.circleci/windows-env.ps1
- run: node --version
- run: yarn --version
- restore_cache:
keys:
- *cache_key_win
- *cache_key_win_fallback
# Install @bazel/bazelisk globally and use that for the first run.
# Workaround for https://github.com/bazelbuild/rules_nodejs/issues/894
# NB: the issue was for @bazel/bazel but the same problem applies to @bazel/bazelisk
- run: yarn global add @bazel/bazelisk@$env:BAZELISK_VERSION
# On Windows `~/` is not resolved when using as a CLI value. `../` results in the same path.
- run: yarn install --frozen-lockfile --non-interactive --cache-folder ../.cache/yarn
- run:
name: Running Yarn install
command: yarn install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
# Yarn's requests sometimes take more than 10mins to complete (especially on Windows).
no_output_timeout: 45m
notify_webhook_on_fail:
description: Notify a webhook about failure
@@ -255,11 +240,7 @@ jobs:
keys:
- *cache_key
- *cache_key_fallback
- run:
name: Running Yarn install
command: yarn install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
# Yarn's requests sometimes take more than 10mins to complete.
no_output_timeout: 45m
- yarn_install
- run: yarn --cwd aio install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
# Make the bazel directories and add a file to them if they don't exist already so that
# persist_to_workspace does not fail.
@@ -675,6 +656,10 @@ jobs:
# variable. It needs to be hardcoded here, because env variables interpolation is
# not supported.
- '/tmp/angular-components-repo'
- run:
# Copy zone.js package to dist/packages-dist, so `angular/components` can also use the local zone.js build.
name: Setting up zone.js release packages.
command: cp -r dist/zone.js-dist/zone.js dist/packages-dist/
- run:
# Updates the `angular/components` `package.json` file to refer to the release output
# inside the `packages-dist` directory.
@@ -718,16 +703,45 @@ jobs:
test_win:
executor: windows-executor
steps:
- setup_win
- checkout
- save_month_to_file
- init_environment
# Setup the proper NodeJS version. The image comes pre-installed with `nvm-windows`.
- run:
name: Install NodeJS version from `.nvmrc`.
command: |
nvm install $(cat .nvmrc)
nvm use $(cat .nvmrc)
- restore_cache:
keys:
- *cache_key_win
- *cache_key_win_fallback
# Install project dependencies, and install Bazelisk globally. This is necessary as
# Windows might error when `bazel` is invoked from the project node modules. The Bazel
# invocation might modify the symlinked project `node_modules` again, causing failures.
- yarn_install
- run: yarn global add @bazel/bazelisk@${BAZELISK_VERSION}
- run:
name: Build all windows CI targets
command: bazel build //packages/compiler-cli/...
command: |
$(yarn global bin)/bazelisk build //packages/compiler-cli/...
no_output_timeout: 15m
- run:
name: Test all windows CI targets
command: bazel test --test_tag_filters="-browser:chromium-local" //packages/compiler-cli/...
command: |
$(yarn global bin)/bazelisk test --test_tag_filters="-browser:chromium-local" //packages/compiler-cli/...
no_output_timeout: 15m
- save_cache:
key: *cache_key_win
paths:
- node_modules
- ~/AppData/Local/bazelisk
workflows:
version: 2
default_workflow:
@@ -786,9 +800,10 @@ workflows:
# since the publishing script expects the legacy outputs layout.
- build-npm-packages
- legacy-unit-tests-saucelabs
- components-repo-unit-tests:
requires:
- build-npm-packages
# TODO(devversion): re-enable once `angular/components` is using `rules_nodejs` v5.
#- components-repo-unit-tests:
# requires:
# - build-npm-packages
- test_zonejs:
requires:
- setup
@@ -811,7 +826,7 @@ workflows:
- saucelabs:
# Testing saucelabs via Bazel currently taking longer than the legacy saucelabs job as it
# each karma_web_test target is provisioning and tearing down browsers which is adding
# a lot of overhead. Running once daily on master only to avoid wasting resources and
# a lot of overhead. Running once daily in the main branch to avoid wasting resources and
# slowing down CI for PRs.
# TODO: Run this job on all branches (including PRs) once karma_web_test targets can
# share provisioned browsers and we can remove the legacy saucelabs job.
@@ -819,6 +834,6 @@ workflows:
- setup
triggers:
- schedule:
<<: *only_on_master
<<: *only_on_main_branch
# Runs monitoring jobs at 10:00AM every day.
cron: '0 10 * * *'
+4 -1
View File
@@ -31,7 +31,10 @@ function setSecretVar() {
local -r originalShellOptions=$(set +o);
set +x -eu -o pipefail;
echo "export $1=\"${2:-}\";" >> $BASH_ENV;
local assignmentStatement="export $1=\"${2:-}\";"
echo "${assignmentStatement}" >> $BASH_ENV;
eval "${assignmentStatement}"
# Restore original shell options.
eval "$originalShellOptions";
+11
View File
@@ -0,0 +1,11 @@
####################################################################################################
# Decrypt GCP Credentials and store them as the Google default credentials.
####################################################################################################
mkdir -p "$HOME/.config/gcloud";
openssl aes-256-cbc -d -in "${PROJECT_ROOT}/.circleci/gcp_token" \
-md md5 -k "$CIRCLE_PROJECT_REPONAME" -out "$HOME/.config/gcloud/application_default_credentials.json"
####################################################################################################
# Set bazel configuration for CircleCI runs.
####################################################################################################
cp "${PROJECT_ROOT}/.circleci/bazel.linux.rc" "$HOME/.bazelrc";
+12 -21
View File
@@ -3,7 +3,6 @@
# Variables
readonly projectDir=$(realpath "$(dirname ${BASH_SOURCE[0]})/..")
readonly envHelpersPath="$projectDir/.circleci/env-helpers.inc.sh";
readonly bashEnvCachePath="$projectDir/.circleci/bash_env_cache";
# Load helpers and make them available everywhere (through `$BASH_ENV`).
source $envHelpersPath;
@@ -72,21 +71,10 @@ setPublicVar SAUCE_READY_FILE_TIMEOUT 120
# the `save_cache` path configuration in `config.yml`
setPublicVar COMPONENTS_REPO_TMP_DIR "/tmp/angular-components-repo"
setPublicVar COMPONENTS_REPO_URL "https://github.com/angular/components.git"
setPublicVar COMPONENTS_REPO_BRANCH "master"
# TODO(BRANCH_RENAME_CLEANUP): fixup branch name to point to main branch
setPublicVar COMPONENTS_REPO_BRANCH "main-branch-rename-do-not-delete"
# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI `config.yml`.
setPublicVar COMPONENTS_REPO_COMMIT "d1cd928714c2d6e3de75f9469ce58b06aad6353c"
####################################################################################################
# Decrypt GCP Credentials and store them as the Google default credentials.
####################################################################################################
mkdir -p "$HOME/.config/gcloud";
openssl aes-256-cbc -d -in "${projectDir}/.circleci/gcp_token" \
-md md5 -k "$CIRCLE_PROJECT_REPONAME" -out "$HOME/.config/gcloud/application_default_credentials.json"
####################################################################################################
# Set bazel configuration for CircleCI runs.
####################################################################################################
cp "${projectDir}/.circleci/bazel.linux.rc" "$HOME/.bazelrc";
setPublicVar COMPONENTS_REPO_COMMIT "e65f5f5bafcd00dbb64387878fb866283909a2dd"
####################################################################################################
# Create shell script in /tmp for Bazel actions to access CI envs without
@@ -98,16 +86,19 @@ echo "export PROJECT_ROOT=\"${PROJECT_ROOT}\";" >> $bazelVarEnv
echo "export CI_BRANCH=\"${CI_BRANCH}\";" >> $bazelVarEnv
echo "export CI_BUILD_URL=\"${CI_BUILD_URL}\";" >> $bazelVarEnv
echo "export CI_COMMIT=\"${CI_COMMIT}\";" >> $bazelVarEnv
echo "export CI_COMMIT_RANGE=\"${CI_COMMIT_RANGE}\";" >> $bazelVarEnv
echo "export CI_PULL_REQUEST=\"${CI_PULL_REQUEST}\";" >> $bazelVarEnv
echo "export CI_REPO_NAME=\"${CI_REPO_NAME}\";" >> $bazelVarEnv
echo "export CI_REPO_OWNER=\"${CI_REPO_OWNER}\";" >> $bazelVarEnv
echo "export CI_SECRET_PAYLOAD_FIREBASE_TOKEN=\"${CI_SECRET_PAYLOAD_FIREBASE_TOKEN}\";" >> $bazelVarEnv
####################################################################################################
# Platform-specific environment setup (which can leverage the base variables from here)
####################################################################################################
## Source `$BASH_ENV` to make the variables available immediately. ##
## ***NOTE: This must remain the last action in this script*** ##
####################################################################################################
####################################################################################################
source $BASH_ENV;
# Conditionally, load additional environment settings based on the current VM
# operating system running. We detect Windows by checking for `%AppData%`.
if [[ -n "${APPDATA}" ]]; then
source ${projectDir}/.circleci/env.windows.sh
else
source ${projectDir}/.circleci/env.linux.sh
fi
+17
View File
@@ -0,0 +1,17 @@
####################################################################################################
# Decrypt GCP Credentials and store them as the Google default credentials.
####################################################################################################
mkdir -p "${APPDATA}/gcloud/";
openssl aes-256-cbc -d -in "${PROJECT_ROOT}/.circleci/gcp_token" \
-md md5 -k "$CIRCLE_PROJECT_REPONAME" -out "${APPDATA}/gcloud/application_default_credentials.json"
####################################################################################################
# Set bazel configuration for CircleCI runs.
####################################################################################################
cp "${PROJECT_ROOT}/.circleci/bazel.windows.rc" "${USERPROFILE}/.bazelrc";
# Expose the Bazelisk version. We need to run Bazelisk globally since Windows has problems launching
# Bazel from a node modules directoy that might be modified by the Bazel Yarn install then.
setPublicVar BAZELISK_VERSION \
"$(cd ${PROJECT_ROOT}; node -p 'require("./package.json").devDependencies["@bazel/bazelisk"]')"
+12 -3
View File
@@ -84,22 +84,31 @@ async function _main() {
/**
* Sort a list of fullpath refs into a list and then provide the first entry.
*
* The sort order will first find master ref, and then any semver ref, followed
* The sort order will first find the the main branch, and then any semver ref, followed
* by the rest of the refs in the order provided.
*
* Branches are sorted in this order as work is primarily done on master, and
* Branches are sorted in this order as work is primarily done on main branches, and
* otherwise on a semver branch. If neither of those were to match, the most
* likely correct branch will be the first one encountered in the list.
*/
function getRefFromBranchList(gitOutput) {
const branches = gitOutput.split('\n').map(b => b.split('/').slice(1).join('/').trim());
return branches.sort((a, b) => {
if (a === 'main') {
return -1;
}
if (b === 'main') {
return 1;
}
// TODO(BRANCH_RENAME_CLEANUP): remove
if (a === 'master') {
return -1;
}
if (b === 'master') {
return 1;
}
const aIsSemver = semverRegex.test(a);
const bIsSemver = semverRegex.test(b);
if (aIsSemver && bIsSemver) {
@@ -132,7 +141,7 @@ function getShaFromRef(ref) {
* by committerdate.
*
* example:
* upstream/master
* upstream/main
* upstream/9.0.x
* upstream/test
* upstream/1.1.x
-57
View File
@@ -1,57 +0,0 @@
# Install Bazel pre-reqs on Windows
# https://docs.bazel.build/versions/master/install-windows.html
# https://docs.bazel.build/versions/master/windows.html
# Install MSYS2 and packages
choco install msys2 --version 20200903.0.0 --no-progress --package-parameters "/NoUpdate"
C:\tools\msys64\usr\bin\bash.exe -l -c "pacman --needed --noconfirm -S zip unzip patch diffutils"
# Add PATH modifications to the Powershell profile. This is the win equivalent of .bash_profile.
# https://docs.microsoft.com/en-us/previous-versions//bb613488(v=vs.85)
new-item -path $profile -itemtype file -force
# Paths for nodejs, npm, yarn, and msys2. Use single quotes to prevent interpolation.
# Add before the original path to use msys2 instead of the installed gitbash.
Add-Content $profile '$Env:path = "${Env:ProgramFiles}\nodejs\;C:\Users\circleci\AppData\Roaming\npm\;${Env:ProgramFiles(x86)}\Yarn\bin\;C:\Users\circleci\AppData\Local\Yarn\bin\;C:\tools\msys64\usr\bin\;" + $Env:path'
# Environment variables for Bazel
Add-Content $profile '$Env:BAZEL_SH = "C:\tools\msys64\usr\bin\bash.exe"'
# Get the bazelisk version devdep and store it in a global var for use in the circleci job.
$bazeliskVersion = & ${Env:ProgramFiles}\nodejs\node.exe -e "console.log(require('./package.json').devDependencies['@bazel/bazelisk'])"
# This is a tricky situation: we want $bazeliskVersion to be evaluated but not $Env:BAZELISK_VERSION.
# Formatting works https://stackoverflow.com/questions/32127583/expand-variable-inside-single-quotes
$bazeliskVersionGlobalVar = '$Env:BAZELISK_VERSION = "{0}"' -f $bazeliskVersion
Add-Content $profile $bazeliskVersionGlobalVar
# Remove the CircleCI checkout SSH override, because it breaks cloning repositories through Bazel.
# See https://circleci.com/gh/angular/angular/401454 for an example.
# TODO: is this really needed? Maybe there's a better way. It doesn't happen on Linux or on Codefresh.
git config --global --unset url.ssh://git@github.com.insteadOf
####################################################################################################
# Decrypt GCP Credentials and store them as the Google default credentials.
####################################################################################################
mkdir ${env:APPDATA}\gcloud
openssl aes-256-cbc -d -in .circleci\gcp_token -md md5 -out "$env:APPDATA\gcloud\application_default_credentials.json" -k "$env:CIRCLE_PROJECT_REPONAME"
####################################################################################################
# Set bazel configuration for CircleCI runs.
####################################################################################################
copy .circleci\bazel.windows.rc ${Env:USERPROFILE}\.bazelrc
####################################################################################################
# Install specific version of node.
####################################################################################################
nvm install 16.10.0
nvm use 16.10.0
# These Bazel prereqs aren't needed because the CircleCI image already includes them.
# choco install yarn --version 1.16.0 --no-progress
# choco install vcredist2015 --version 14.0.24215.20170201
# We don't need VS Build Tools for the tested bazel targets.
# If it's needed again, uncomment these lines.
# VS Build Tools are needed for Bazel C++ targets (like com_google_protobuf)
# choco install visualstudio2019buildtools --version 16.1.2.0 --no-progress --package-parameters "--add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.Component.VC.Runtime.UCRTSDK --add Microsoft.VisualStudio.Component.Windows10SDK.17763"
# Add-Content $profile '$Env:BAZEL_VC = "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\VC\"'
# Python is needed for Bazel Python targets
# choco install python --version 3.5.1 --no-progress
@@ -5,7 +5,7 @@ body:
- type: dropdown
id: affected-packages
attributes:
label: Which @angular/* package(s) are relevant/releated to the feature request?
label: Which @angular/* package(s) are relevant/related to the feature request?
options:
- animations
- bazel
+6 -2
View File
@@ -4,11 +4,15 @@ on:
pull_request_target:
types: [opened, synchronize, reopened]
# Declare default permissions as read only.
permissions:
contents: read
jobs:
labels:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: angular/dev-infra/github-actions/commit-message-based-labels@fb9b744a4903d0d17e1fccfcdec531cb601b3e47
- uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # tag=v3.0.0
- uses: angular/dev-infra/github-actions/commit-message-based-labels@129a5ccbcc73d7ca960d8c166d7400bf2e94cd3d
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+5 -1
View File
@@ -5,11 +5,15 @@ on:
# Run at 14:00 every day
- cron: '0 14 * * *'
# Declare default permissions as read only.
permissions:
contents: read
jobs:
feature_triage:
if: github.repository == 'angular/angular'
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/feature-request@fb9b744a4903d0d17e1fccfcdec531cb601b3e47
- uses: angular/dev-infra/github-actions/feature-request@129a5ccbcc73d7ca960d8c166d7400bf2e94cd3d
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+5 -1
View File
@@ -5,11 +5,15 @@ on:
# Run at 16:00 every day
- cron: '0 16 * * *'
# Declare default permissions as read only.
permissions:
contents: read
jobs:
lock_closed:
if: github.repository == 'angular/angular'
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/lock-closed@fb9b744a4903d0d17e1fccfcdec531cb601b3e47
- uses: angular/dev-infra/github-actions/lock-closed@129a5ccbcc73d7ca960d8c166d7400bf2e94cd3d
with:
lock-bot-key: ${{ secrets.LOCK_BOT_PRIVATE_KEY }}
+11 -6
View File
@@ -4,11 +4,16 @@ on:
schedule:
- cron: '0 0 * * 0'
push:
branches: [master]
branches: [
main,
# TODO(BRANCH_RENAME_CLEANUP): remove
master,
]
workflow_dispatch:
# Declare default permissions as read only.
permissions: read-all
permissions:
contents: read
jobs:
analysis:
@@ -22,12 +27,12 @@ jobs:
steps:
- name: 'Checkout code'
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0
uses: actions/checkout@230611dbd0eb52da1e1f4f7bc8bb0c3a339fc8b7
with:
persist-credentials: false
- name: 'Run analysis'
uses: ossf/scorecard-action@c8416b0b2bf627c349ca92fc8e3de51a64b005cf # v1.0.2
uses: ossf/scorecard-action@3662744abc9b750123cb8965fef31e3802d52da5
with:
results_file: results.sarif
results_format: sarif
@@ -36,7 +41,7 @@ jobs:
# Upload the results as artifacts.
- name: 'Upload artifact'
uses: actions/upload-artifact@82c141cc518b40d92cc801eee768e7aafc9c2fa2 # v2.3.1
uses: actions/upload-artifact@2244c8200304ec9588bf9399eac622d9fadc28c4
with:
name: SARIF file
path: results.sarif
@@ -44,6 +49,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # v1.0.26
uses: github/codeql-action/upload-sarif@040feefecff4ae0fc15c110822a5f96516b0629e
with:
sarif_file: results.sarif
+4
View File
@@ -6,6 +6,10 @@
*.log
node_modules
# CircleCI temporary file for cache key computation.
# See `save_month_to_file` in `.circleci/config.yml`.
month.txt
# Include when developing application packages.
pubspec.lock
.c9
+2 -2
View File
@@ -1,4 +1,4 @@
import {CaretakerConfig} from '@angular/dev-infra-private/ng-dev/caretaker/config';
import {CaretakerConfig} from '@angular/dev-infra-private/ng-dev';
/** The configuration for `ng-dev caretaker` commands. */
export const caretaker: CaretakerConfig = {
@@ -14,7 +14,7 @@ export const caretaker: CaretakerConfig = {
{
name: 'Initial Triage Queue',
query: `is:open no:milestone`,
}
},
],
caretakerGroup: 'angular-caretaker',
};
+2 -2
View File
@@ -1,4 +1,4 @@
import {CommitMessageConfig} from '@angular/dev-infra-private/ng-dev/commit-message/config';
import {CommitMessageConfig} from '@angular/dev-infra-private/ng-dev';
/**
* The configuration for `ng-dev commit-message` commands.
@@ -36,5 +36,5 @@ export const commitMessage: CommitMessageConfig = {
'upgrade',
've',
'zone.js',
]
],
};
+4 -6
View File
@@ -1,13 +1,11 @@
import {FormatConfig} from '@angular/dev-infra-private/ng-dev/format/config';
import {FormatConfig} from '@angular/dev-infra-private/ng-dev';
/**
* Configuration for the `ng-dev format` command.
*/
export const format: FormatConfig = {
'prettier': {
'matchers': [
'**/*.{yaml,yml}',
]
'matchers': ['**/*.{yaml,yml}'],
},
'clang-format': {
'matchers': [
@@ -31,7 +29,7 @@ export const format: FormatConfig = {
'!packages/core/src/i18n/locale_en.ts',
'!packages/common/locales/closure-locale.ts',
'!packages/common/src/i18n/currencies.ts',
]
],
},
'buildifier': true
'buildifier': true,
};
+1 -1
View File
@@ -1,4 +1,4 @@
import {GithubConfig} from '@angular/dev-infra-private/ng-dev/utils/config';
import {GithubConfig} from '@angular/dev-infra-private/ng-dev';
/**
* Github configuration for the `ng-dev` command. This repository is used as
+2 -2
View File
@@ -1,4 +1,4 @@
import {PullRequestConfig} from '@angular/dev-infra-private/ng-dev/pr/config';
import {PullRequestConfig} from '@angular/dev-infra-private/ng-dev';
/**
* Configuration for the merge tool in `ng-dev`. This sets up the labels which
@@ -19,5 +19,5 @@ export const pullRequest: PullRequestConfig = {
// `dev-infra` and `docs-infra` are not affecting the public NPM packages. Similarly,
// the `bazel` package is not considered part of the public API so that features
// can land in patch branches.
targetLabelExemptScopes: ['dev-infra', 'docs-infra', 'bazel']
targetLabelExemptScopes: ['dev-infra', 'docs-infra', 'bazel'],
};
+2 -8
View File
@@ -1,4 +1,4 @@
import {ReleaseConfig} from '@angular/dev-infra-private/ng-dev/release/config';
import {ReleaseConfig} from '@angular/dev-infra-private/ng-dev';
import {join} from 'path';
/** Configuration for the `ng-dev release` command. */
@@ -30,13 +30,7 @@ export const release: ReleaseConfig = {
return buildTargetPackages('dist/release-output', false, 'Release', /* isRelease */ true);
},
releaseNotes: {
hiddenScopes: [
'aio',
'dev-infra',
'docs-infra',
'zone.js',
'devtools',
],
hiddenScopes: ['aio', 'dev-infra', 'docs-infra', 'zone.js', 'devtools'],
},
releasePrLabels: ['comp: build & ci', 'action: merge', 'PullApprove: disable'],
};
+9 -8
View File
@@ -224,7 +224,7 @@ groups:
users:
- alxhub
- crisbeto
- jelbourn
- ~jelbourn
- jessicajaniuk
# =========================================================
@@ -244,7 +244,7 @@ groups:
'aio/content/guide/angular-compiler-options.md',
'aio/content/guide/aot-compiler.md',
'aio/content/guide/aot-metadata-errors.md',
'aio/content/guide/template-typecheck.md '
'aio/content/guide/template-typecheck.md'
])
reviewers:
users:
@@ -395,6 +395,7 @@ groups:
'aio/content/guide/template-expression-operators.md',
'aio/content/examples/template-expression-operators/**',
'aio/content/guide/pipes.md',
'aio/content/guide/pipes-custom-data-trans.md',
'aio/content/examples/pipes/**',
'aio/content/images/guide/pipes/**',
'aio/content/guide/providers.md',
@@ -1038,12 +1039,12 @@ groups:
'aio/content/guide/migration-module-with-providers.md',
'aio/content/guide/static-query-migration.md',
'aio/content/guide/update-to-latest-version.md',
'aio/content/guide/ivy-compatibility.md',
'aio/content/guide/ivy-compatibility-examples.md'
])
reviewers:
users:
- alxhub
- AndrewKushnir
- atscott
- jelbourn
# =========================================================
@@ -1284,7 +1285,7 @@ groups:
- alxhub
- atscott
- dylhunn
- jelbourn
- ~jelbourn
- jessicajaniuk
- pkozlowski-opensource
reviews:
@@ -1311,7 +1312,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- jelbourn
- ~jelbourn
- jessicajaniuk
- pkozlowski-opensource
reviews:
@@ -1338,7 +1339,7 @@ groups:
- AndrewKushnir
- atscott
- dylhunn
- jelbourn
- ~jelbourn
- jessicajaniuk
- pkozlowski-opensource
@@ -1363,5 +1364,5 @@ groups:
- AndrewKushnir
- andrewseguin
- dgp1130
- jelbourn
- ~jelbourn
- josephperrott
+10 -1
View File
@@ -1,10 +1,12 @@
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
package(default_visibility = ["//visibility:public"])
exports_files([
"LICENSE",
"karma-js.conf.js",
"browser-providers.conf.js",
"scripts/ci/track-payload-size.sh",
"scripts/ci/bazel-payload-size.sh",
"scripts/ci/payload-size.sh",
"scripts/ci/payload-size.js",
"package.json",
@@ -56,3 +58,10 @@ config_setting(
name = "stamp",
values = {"stamp": "true"},
)
nodejs_binary(
name = "yarn_vendored",
data = [".yarn/releases/yarn-1.22.17.cjs"],
entry_point = ".yarn/releases/yarn-1.22.17.cjs",
visibility = ["//integration:__subpackages__"],
)
+163 -6561
View File
File diff suppressed because it is too large Load Diff
+6557
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -53,6 +53,7 @@ Get started with Angular, learn the fundamentals and explore advanced topics on
- [Server Side Rendering][ssr]
- [Schematics][schematics]
- [Lazy Loading][lazyloading]
- [Animations][animations]
## Development Setup
@@ -157,3 +158,4 @@ Join the conversation and help the community.
[stackoverflow]: https://stackoverflow.com/questions/tagged/angular
[youtube]: https://youtube.com/angular
[meetup]: https://www.meetup.com/find/?keywords=angular
[animations]: https://angular.io/guide/animations
+30 -15
View File
@@ -5,13 +5,16 @@ workspace(
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch rules_nodejs so we can install our npm dependencies
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "ddb78717b802f8dd5d4c01c340ecdc007c8ced5c1df7db421d0df3d642ea0580",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/4.6.0/rules_nodejs-4.6.0.tar.gz"],
sha256 = "3ceb1e5b5dcad5fa2ad8870a20201cfbb9c9c63cac4055c9ab370034c765297f",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.3.0/rules_nodejs-5.3.0.tar.gz"],
)
load("@build_bazel_rules_nodejs//:repositories.bzl", "build_bazel_rules_nodejs_dependencies")
build_bazel_rules_nodejs_dependencies()
# The PKG rules are needed to build tar packages for integration tests. The builtin
# rule in `@bazel_tools` is not Windows compatible and outdated.
http_archive(
@@ -23,28 +26,38 @@ http_archive(
],
)
# Check the rules_nodejs version and download npm dependencies
# Note: bazel (version 2 and after) will check the .bazelversion file so we don't need to
# assert on that.
load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install")
load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains")
check_rules_nodejs_version(minimum_version_string = "2.2.0")
# Setup the Node.js toolchain
node_repositories(
nodejs_register_toolchains(
name = "nodejs",
node_version = "16.10.0",
package_json = ["//:package.json"],
)
# Download npm dependencies.
load("@build_bazel_rules_nodejs//:index.bzl", "yarn_install")
load("//integration:npm_package_archives.bzl", "npm_package_archives")
yarn_install(
name = "npm",
# Note that we add the postinstall script here so that the dependencies are re-installed
# Note that we add the postinstall scripts here so that the dependencies are re-installed
# when the postinstall patches are modified.
data = ["//tools:postinstall-patches.js"],
data = [
"//:.yarn/releases/yarn-1.22.17.cjs",
"//:.yarnrc",
"//:scripts/puppeteer-chromedriver-versions.js",
"//:scripts/webdriver-manager-update.js",
"//tools:postinstall-patches.js",
],
# Currently disabled due to:
# 1. Missing Windows support currently.
# 2. Incompatibilites with the `ts_library` rule.
exports_directories_only = False,
manual_build_file_contents = npm_package_archives(),
package_json = "//:package.json",
# We prefer to symlink the `node_modules` to only maintain a single install.
# See https://github.com/angular/dev-infra/pull/446#issuecomment-1059820287 for details.
symlink_node_modules = True,
yarn = "//:.yarn/releases/yarn-1.22.17.cjs",
yarn_lock = "//:yarn.lock",
)
@@ -64,7 +77,9 @@ browser_repositories()
load("@build_bazel_rules_nodejs//toolchains/esbuild:esbuild_repositories.bzl", "esbuild_repositories")
esbuild_repositories()
esbuild_repositories(
npm_repository = "npm",
)
load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
+1 -1
View File
@@ -2,7 +2,7 @@
Everything in this folder is part of the documentation project. This includes:
* the web site for displaying the documentation
* the web site for displaying the documentation.
* the dgeni configuration for converting source files to rendered files that can be viewed in the web site.
* the tooling for setting up examples for development; and generating live-example and zip files from the examples.
+13 -13
View File
@@ -1,5 +1,5 @@
# Image metadata and config
FROM debian:buster
FROM debian:bullseye
LABEL name="angular.io PR preview" \
description="This image implements the PR preview functionality for angular.io." \
@@ -72,29 +72,29 @@ RUN mkdir /var/log/aio
# Add extra package sources
RUN apt-get update -y && apt-get install -y curl=7.64.0-4+deb10u1
RUN curl --silent --show-error --location https://deb.nodesource.com/setup_12.x | bash -
RUN apt-get update -y && apt-get install -y curl
RUN curl --silent --show-error --location https://deb.nodesource.com/setup_14.x | bash -
RUN curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
# Install packages
# NOTE: Some packages (such as `nginx`, `nodejs`, `openssl`) make older versions unavailable on the
# repositories, so we cannot pin to specific versions for these packages :(
# See for example:
# NOTE: Many packages make older versions unavailable on the repositories, so we cannot pin to
# specific versions :(
# See, for example:
# - https://github.com/nodesource/distributions/issues/33
# - https://askubuntu.com/questions/715104/how-can-i-downgrade-openssl-via-apt-get
RUN apt-get update -y && apt-get install -y \
cron=3.0pl1-134+deb10u1 \
dnsmasq=2.80-1 \
nano=3.2-3 \
cron \
dnsmasq \
nano \
nginx \
nodejs \
openssl \
rsyslog=8.1901.0-1 \
vim=2:8.1.0875-5 \
yarn=1.22.4-1
RUN yarn global add pm2@4.4.0
rsyslog \
vim \
yarn=1.22.18-1
RUN yarn global add pm2@5.2.0
# Set up log rotation
@@ -1,10 +1,10 @@
// Imports
import fetch from 'node-fetch';
import fetch, {RequestInit} from 'node-fetch';
import {assertNotMissingOrEmpty} from './utils';
// Constants
const CIRCLE_CI_API_URL = 'https://circleci.com/api/v1.1/project/github';
const CIRCLE_CI_API_URL = 'https://circleci.com/api/v2/project/gh';
// Interfaces - Types
export interface ArtifactInfo {
@@ -32,8 +32,6 @@ export interface BuildInfo {
* A Helper that can interact with the CircleCI API.
*/
export class CircleCiApi {
private tokenParam = `circle-token=${this.circleCiToken}`;
/**
* Construct a helper that can interact with the CircleCI REST API.
* @param githubOrg The Github organisation whose repos we want to access in CircleCI (e.g.
@@ -51,6 +49,15 @@ export class CircleCiApi {
assertNotMissingOrEmpty('circleCiToken', circleCiToken);
}
public async fetchFromCircleCi(url: string, params: RequestInit = {}) {
params.headers = {...params.headers, 'Circle-Token': this.circleCiToken};
const response = await fetch(url, params);
if (response.status !== 200) {
throw new Error(`${url}: ${response.status} - ${response.statusText}`);
}
return response;
}
/**
* Get the info for a build from the CircleCI API
* @param buildNumber The CircleCI build number that generated the artifact.
@@ -58,11 +65,8 @@ export class CircleCiApi {
*/
public async getBuildInfo(buildNumber: number): Promise<BuildInfo> {
try {
const baseUrl = `${CIRCLE_CI_API_URL}/${this.githubOrg}/${this.githubRepo}/${buildNumber}`;
const response = await fetch(`${baseUrl}?${this.tokenParam}`);
if (response.status !== 200) {
throw new Error(`${baseUrl}: ${response.status} - ${response.statusText}`);
}
const url = `${CIRCLE_CI_API_URL}/${this.githubOrg}/${this.githubRepo}/job/${buildNumber}`;
const response = await this.fetchFromCircleCi(url);
return response.json();
} catch (error) {
throw new Error(`CircleCI build info request failed (${(error as Error).message})`);
@@ -77,9 +81,9 @@ export class CircleCiApi {
public async getBuildArtifactUrl(buildNumber: number, artifactPath: string): Promise<string> {
const baseUrl = `${CIRCLE_CI_API_URL}/${this.githubOrg}/${this.githubRepo}/${buildNumber}`;
try {
const response = await fetch(`${baseUrl}/artifacts?${this.tokenParam}`);
const artifacts = await response.json() as ArtifactResponse;
const artifact = artifacts.find(item => item.path === artifactPath);
const response = await this.fetchFromCircleCi(`${baseUrl}/artifacts`);
const artifacts = await response.json() as {items: ArtifactResponse};
const artifact = artifacts.items.find(item => item.path === artifactPath);
if (!artifact) {
throw new Error(`Missing artifact (${artifactPath}) for CircleCI build: ${buildNumber}`);
}
@@ -1,5 +1,4 @@
import * as fs from 'fs';
import fetch from 'node-fetch';
import {dirname} from 'path';
import {mkdir} from 'shelljs';
import {promisify} from 'util';
@@ -63,11 +62,7 @@ export class BuildRetriever {
await new Promise(resolve => fs.exists(outPath, exists => resolve(exists)));
if (!downloadExists) {
const url = await this.api.getBuildArtifactUrl(buildNum, artifactPath);
const response = await fetch(url, {size: this.downloadSizeLimit});
if (response.status !== 200) {
throw new PreviewServerError(
response.status, `Error ${response.status} - ${response.statusText}`);
}
const response = await this.api.fetchFromCircleCi(url, {size: this.downloadSizeLimit});
const buffer = await response.buffer();
mkdir('-p', dirname(outPath));
await promisify(fs.writeFile)(outPath, buffer);
@@ -4,7 +4,7 @@ import {CircleCiApi} from '../../lib/common/circle-ci-api';
const ORG = 'testorg';
const REPO = 'testrepo';
const TOKEN = 'xxxx';
const BASE_URL = `https://circleci.com/api/v1.1/project/github/${ORG}/${REPO}`;
const BASE_URL = `https://circleci.com/api/v2/project/gh/${ORG}/${REPO}`;
describe('CircleCIApi', () => {
describe('constructor()', () => {
@@ -24,6 +24,18 @@ describe('CircleCIApi', () => {
});
});
describe('fetchFromCircleCI', () => {
it('should include the authentication token in the headers on every request', async () => {
const api = new CircleCiApi(ORG, REPO, TOKEN);
const request = nock(BASE_URL)
.get('/')
.matchHeader('Circle-Token', TOKEN)
.reply(200);
await api.fetchFromCircleCi(`${BASE_URL}/`);
request.done();
})
})
describe('getBuildInfo', () => {
it('should make a request to the CircleCI API for the given build number', async () => {
const api = new CircleCiApi(ORG, REPO, TOKEN);
@@ -31,7 +43,7 @@ describe('CircleCIApi', () => {
const expectedBuildInfo: any = { org: ORG, repo: REPO, build_num: buildNum };
const request = nock(BASE_URL)
.get(`/${buildNum}?circle-token=${TOKEN}`)
.get(`/job/${buildNum}`)
.reply(200, expectedBuildInfo);
const buildInfo = await api.getBuildInfo(buildNum);
@@ -43,17 +55,17 @@ describe('CircleCIApi', () => {
const api = new CircleCiApi(ORG, REPO, TOKEN);
const buildNum = 12345;
const errorMessage = 'Invalid request';
const request = nock(BASE_URL).get(`/${buildNum}?circle-token=${TOKEN}`);
const request = nock(BASE_URL).get(`/job/${buildNum}`);
request.replyWithError(errorMessage);
await expectAsync(api.getBuildInfo(buildNum)).toBeRejectedWithError(
`CircleCI build info request failed ` +
`(request to ${BASE_URL}/${buildNum}?circle-token=${TOKEN} failed, reason: ${errorMessage})`);
`(request to ${BASE_URL}/job/${buildNum} failed, reason: ${errorMessage})`);
request.reply(404, errorMessage);
await expectAsync(api.getBuildInfo(buildNum)).toBeRejectedWithError(
`CircleCI build info request failed ` +
`(request to ${BASE_URL}/${buildNum}?circle-token=${TOKEN} failed, reason: ${errorMessage})`);
`(request to ${BASE_URL}/job/${buildNum} failed, reason: ${errorMessage})`);
});
});
@@ -65,8 +77,8 @@ describe('CircleCIApi', () => {
const artifact1: any = { path: 'some/path/1', url: 'https://url/1' };
const artifact2: any = { path: 'some/path/2', url: 'https://url/2' };
const request = nock(BASE_URL)
.get(`/${buildNum}/artifacts?circle-token=${TOKEN}`)
.reply(200, [artifact0, artifact1, artifact2]);
.get(`/${buildNum}/artifacts`)
.reply(200, {items: [artifact0, artifact1, artifact2]});
await expectAsync(api.getBuildArtifactUrl(buildNum, 'some/path/1')).toBeResolvedTo('https://url/1');
request.done();
@@ -77,17 +89,17 @@ describe('CircleCIApi', () => {
const api = new CircleCiApi(ORG, REPO, TOKEN);
const buildNum = 12345;
const errorMessage = 'Invalid request';
const request = nock(BASE_URL).get(`/${buildNum}/artifacts?circle-token=${TOKEN}`);
const request = nock(BASE_URL).get(`/${buildNum}/artifacts`);
request.replyWithError(errorMessage);
await expectAsync(api.getBuildArtifactUrl(buildNum, 'some/path/1')).toBeRejectedWithError(
`CircleCI artifact URL request failed ` +
`(request to ${BASE_URL}/${buildNum}/artifacts?circle-token=${TOKEN} failed, reason: ${errorMessage})`);
`(request to ${BASE_URL}/${buildNum}/artifacts failed, reason: ${errorMessage})`);
request.reply(404, errorMessage);
await expectAsync(api.getBuildArtifactUrl(buildNum, 'some/path/1')).toBeRejectedWithError(
`CircleCI artifact URL request failed ` +
`(request to ${BASE_URL}/${buildNum}/artifacts?circle-token=${TOKEN} failed, reason: ${errorMessage})`);
`(request to ${BASE_URL}/${buildNum}/artifacts failed, reason: ${errorMessage})`);
});
it('should throw an error if the response does not contain the specified artifact', async () => {
@@ -97,8 +109,8 @@ describe('CircleCIApi', () => {
const artifact1: any = { path: 'some/path/1', url: 'https://url/1' };
const artifact2: any = { path: 'some/path/2', url: 'https://url/2' };
nock(BASE_URL)
.get(`/${buildNum}/artifacts?circle-token=${TOKEN}`)
.reply(200, [artifact0, artifact1, artifact2]);
.get(`/${buildNum}/artifacts`)
.reply(200, {items: [artifact0, artifact1, artifact2]});
await expectAsync(api.getBuildArtifactUrl(buildNum, 'some/path/3')).toBeRejectedWithError(
`CircleCI artifact URL request failed ` +
@@ -160,7 +160,7 @@ describe('BuildRetriever', () => {
const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(404, 'No such artifact');
await expectAsync(retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH)).
toBeRejectedWithError('CircleCI artifact download failed (Error 404 - Not Found)');
toBeRejectedWithError(`CircleCI artifact download failed (${BASE_URL}/some/path/build.zip: 404 - Not Found)`);
artifactRequest.done();
});
@@ -25,8 +25,8 @@ Necessary secrets:
- Generate new token with the `public_repo` scope.
2. `CIRCLE_CI_TOKEN`
- Visit https://circleci.com/gh/angular/angular/edit#api.
- Create an API token with `Build Artifacts` scope.
- Visit https://app.circleci.com/settings/user/tokens.
- Create a user API token.
## Save secrets on the VM
+34 -17
View File
@@ -1,5 +1,6 @@
# Persistent disk cache
Angular CLI saves a number of cachable operations on disk by default.
When you re-run the same build, the build system restores the state of the previous build and re-uses previously performed operations, which decreases the time taken to build and test your applications and libraries.
@@ -7,9 +8,10 @@ When you re-run the same build, the build system restores the state of the previ
To amend the default cache settings, add the `cli.cache` object to your [Workspace Configuration](guide/workspace-config).
The object goes under `cli.cache` at the top level of the file, outside the `projects` sections.
```json
<code-example format="json" language="json">
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"$schema": "./node_modules/&commat;angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"cache": {
@@ -18,27 +20,35 @@ The object goes under `cli.cache` at the top level of the file, outside the `pro
},
"projects": {}
}
```
</code-example>
For more information, see [cache options](guide/workspace-config#cache-options).
### Enabling and disabling the cache
Caching is enabled by default. To disable caching run the following command:
```bash
Caching is enabled by default.
To disable caching run the following command:
<code-example format="shell" language="shell">
ng config cli.cache.enabled false
```
</code-example>
To re-enable caching, set `cli.cache.enabled` to `true`.
### Cache environments
By default, disk cache is only enabled for local environments.
To enable caching for all environments, run the following command:
```bash
<code-example format="shell" language="shell">
ng config cli.cache.environment all
```
</code-example>
For more information, see `environment` in [cache options](guide/workspace-config#cache-options).
@@ -50,11 +60,14 @@ The Angular CLI checks for the presence and value of the `CI` environment variab
### Cache path
By default, `.angular/cache` is used as a base directory to store cache results. To change this path, run the following command:
By default, `.angular/cache` is used as a base directory to store cache results.
To change this path, run the following command:
<code-example format="shell" language="shell">
```bash
ng config cli.cache.path ".cache/ng"
```
</code-example>
### Clearing the cache
@@ -62,14 +75,18 @@ To clear the cache, run one of the following commands.
To clear the cache on Unix-based operating systems:
```bash
<code-example format="shell" language="shell">
rm -rf .angular/cache
```
</code-example>
To clear the cache on Windows:
```bash
rmdir /s /q .angular\cache
```
<code-example format="shell" language="shell">
For more information, see [rm command](https://man7.org/linux/man-pages/man1/rm.1.html) and [rmdir command](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/rmdir).
rmdir /s /q .angular\cache
</code-example>
For more information, see [rm command](https://man7.org/linux/man-pages/man1/rm.1.html) and [rmdir command](https://docs.microsoft.com/windows-server/administration/windows-commands/rmdir).
+46 -24
View File
@@ -7,30 +7,36 @@ The Angular CLI is a command-line interface tool that you use to initialize, dev
Major versions of Angular CLI follow the supported major version of Angular, but minor versions can be released separately.
Install the CLI using the `npm` package manager:
<code-example language="bash">
npm install -g @angular/cli
<code-example format="shell" language="shell">
npm install -g &commat;angular/cli
</code-example>
For details about changes between versions, and information about updating from previous releases,
see the Releases tab on GitHub: https://github.com/angular/angular-cli/releases
For details about changes between versions, and information about updating from previous releases, see the Releases tab on GitHub: https://github.com/angular/angular-cli/releases
## Basic workflow
Invoke the tool on the command line through the `ng` executable.
Online help is available on the command line.
Enter the following to list commands or options for a given command (such as [generate](cli/generate)) with a short description.
Enter the following to list commands or options for a given command \(such as [generate](cli/generate)\) with a short description.
<code-example format="shell" language="shell">
<code-example language="bash">
ng help
ng generate --help
</code-example>
To create, build, and serve a new, basic Angular project on a development server, go to the parent directory of your new workspace use the following commands:
<code-example language="bash">
<code-example format="shell" language="shell">
ng new my-first-project
cd my-first-project
ng serve
</code-example>
In your browser, open http://localhost:4200/ to see the new application run.
@@ -38,9 +44,10 @@ When you use the [ng serve](cli/serve) command to build an application and serve
<div class="alert is-helpful">
When you run `ng new my-first-project` a new folder, named `my-first-project`, will be created in the current working directory. Since you want to be able to create files inside that folder, make sure you have sufficient rights in the current working directory before running the command.
When you run `ng new my-first-project` a new folder, named `my-first-project`, will be created in the current working directory.
Since you want to be able to create files inside that folder, make sure you have sufficient rights in the current working directory before running the command.
If the current working directory is not the right place for your project, you can change to a more appropriate directory by running `cd <path-to-other-directory>` first.
If the current working directory is not the right place for your project, you can change to a more appropriate directory by running `cd <path-to-other-directory>`.
</div>
@@ -58,7 +65,7 @@ You can edit the generated files directly, or add to and modify them using CLI c
Use the [ng generate](cli/generate) command to add new files for additional components and services, and code for new pipes, directives, and so on.
Commands such as [add](cli/add) and [generate](cli/generate), which create or operate on applications and libraries, must be executed from within a workspace or project folder.
* See more about the [Workspace file structure](guide/file-structure).
* See more about the [Workspace file structure](guide/file-structure).
### Workspace and project configuration
@@ -66,10 +73,15 @@ A single workspace configuration file, `angular.json`, is created at the top lev
This is where you can set per-project defaults for CLI command options, and specify configurations to use when the CLI builds a project for different targets.
The [ng config](cli/config) command lets you set and retrieve configuration values from the command line, or you can edit the `angular.json` file directly.
Note that option names in the configuration file must use [camelCase](guide/glossary#case-types), while option names supplied to commands can use either camelCase or dash-case.
* See more about [Workspace Configuration](guide/workspace-config).
* See the [complete schema](https://github.com/angular/angular-cli/wiki/angular-workspace) for `angular.json`.
<div class="alert is-helpful">
**NOTE**: <br />
Option names in the configuration file must use [camelCase](guide/glossary#case-types), while option names supplied to commands must be dash-case.
</div>
* See more about [Workspace Configuration](guide/workspace-config).
## CLI command-language syntax
@@ -77,34 +89,44 @@ Command syntax is shown as follows:
`ng` *commandNameOrAlias* *requiredArg* [*optionalArg*] `[options]`
* Most commands, and some options, have aliases. Aliases are shown in the syntax statement for each command.
* Most commands, and some options, have aliases.
Aliases are shown in the syntax statement for each command.
* Option names are prefixed with a double dash (--).
Option aliases are prefixed with a single dash (-).
* Option names are prefixed with a double dash \(`--`\) characters.
Option aliases are prefixed with a single dash \(`-`\) character.
Arguments are not prefixed.
For example:
<code-example language="bash">
ng build my-app -c production
<code-example format="shell" language="shell">
ng build my-app -c production
</code-example>
* Typically, the name of a generated artifact can be given as an argument to the command or specified with the --name option.
* Typically, the name of a generated artifact can be given as an argument to the command or specified with the `--name` option.
* Argument and option names can be given in either
[camelCase or dash-case](guide/glossary#case-types).
`--myOptionName` is equivalent to `--my-option-name`.
* Argument and option names can be given in either [camelCase or dash-case](guide/glossary#case-types).
`--myOptionName` is equivalent to `--my-option-name`.
### Boolean options
Boolean options have two forms: `--this-option` sets the flag to `true`, `--no-this-option` sets it to `false`.
If neither option is supplied, the flag remains in its default state, as listed in the reference documentation.
### Relative paths
Options that specify files can be given as absolute paths, or as paths relative to the current working directory, which is generally either the workspace or project root.
### Schematics
The [ng generate](cli/generate) and [ng add](cli/add) commands take as an argument the artifact or library to be generated or added to the current project.
The [ng generate](cli/generate) and [ng add](cli/add) commands take, as an argument, the artifact or library to be generated or added to the current project.
In addition to any general options, each artifact or library defines its own options in a *schematic*.
Schematic options are supplied to the command in the same format as immediate command options.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+20 -4
View File
@@ -20,14 +20,18 @@ This ID is a string that looks like `UA-123456-12`.
You can choose to use a descriptive string as the key value, or be assigned a random key when you run the CLI command.
For example, the following command adds a configuration key named "tracking".
<code-example language="sh">
<code-example format="shell" language="shell">
ng config --global cli.analyticsSharing.tracking UA-123456-12
</code-example>
To turn off this feature, run the following command:
<code-example language="sh">
<code-example format="shell" language="shell">
ng config --global cli.analyticsSharing undefined
</code-example>
## Per user tracking
@@ -35,12 +39,24 @@ ng config --global cli.analyticsSharing undefined
You can add a custom user ID to the global configuration, in order to identify unique usage of commands and flags.
If that user enables CLI analytics for their own project, your analytics display tracks and labels their individual usage.
<code-example language="sh">
<code-example format="shell" language="shell">
ng config --global cli.analyticsSharing.uuid SOME_USER_NAME
</code-example>
To generate a new random user ID, run the following command:
<code-example language="sh">
<code-example format="shell" language="shell">
ng config --global cli.analyticsSharing.uuid ""
</code-example>
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+25 -6
View File
@@ -4,17 +4,36 @@
@shortDescription Expression has changed after it was checked
@description
Angular throws an `ExpressionChangedAfterItHasBeenCheckedError` when an expression value has been changed after change detection has completed. Angular only throws this error in development mode.
In development mode, Angular performs an additional check after each change detection run, to ensure the bindings haven’t changed. This catches errors where the view is left in an inconsistent state. This can occur, for example, if a method or getter returns a different value each time it is called, or if a child component changes values on its parent. If either of these occur, this is a sign that change detection is not stabilized. Angular throws the error to ensure data is always reflected correctly in the view, which prevents erratic UI behavior or a possible infinite loop.
Angular throws an `ExpressionChangedAfterItHasBeenCheckedError` when an expression value has been changed after change detection has completed.
Angular only throws this error in development mode.
This error commonly occurs when you’ve added template expressions or begun to implement lifecycle hooks like `ngAfterViewInit` or `ngOnChanges`. It is also common when dealing with loading status and asynchronous operations, or a child component changes its parent bindings.
In development mode, Angular performs an additional check after each change detection run, to ensure the bindings haven't changed.
This catches errors where the view is left in an inconsistent state.
This can occur, for example, if a method or getter returns a different value each time it is called, or if a child component changes values on its parent.
If either of these occur, this is a sign that change detection is not stabilized
Angular throws the error to ensure data is always reflected correctly in the view, which prevents erratic UI behavior or a possible infinite loop.
This error commonly occurs when you've added template expressions or have begun to implement lifecycle hooks like `ngAfterViewInit` or `ngOnChanges`.
It is also common when dealing with loading status and asynchronous operations, or when a child component changes its parent bindings.
@debugging
The [source maps](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map) generated by the CLI are very useful when debugging. Navigate up the call stack until you find a template expression where the value displayed in the error has changed.
Ensure that there are no changes to the bindings in the template after change detection is run. This often means refactoring to use the correct [component lifecycle hook](guide/lifecycle-hooks) for your use case. If the issue exists within `ngAfterViewInit`, the recommended solution is to use a constructor or `ngOnInit` to set initial values, or use `ngAfterContentInit` for other value bindings.
The [source maps](https://developer.mozilla.org/docs/Tools/Debugger/How_to/Use_a_source_map) generated by the CLI are very useful when debugging.
Navigate up the call stack until you find a template expression where the value displayed in the error has changed.
Ensure that there are no changes to the bindings in the template after change detection is run.
This often means refactoring to use the correct [component lifecycle hook](guide/lifecycle-hooks) for your use case.
If the issue exists within `ngAfterViewInit`, the recommended solution is to use a constructor or `ngOnInit` to set initial values, or use `ngAfterContentInit` for other value bindings.
If you are binding to methods in the view, ensure that the invocation does not update any of the other bindings in the template.
Read more about which solution is right for you in ['Everything you need to know about the "ExpressionChangedAfterItHasBeenCheckedError" error'](https://indepth.dev/posts/1001/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error) and why this is useful at ['Angular Debugging "Expression has changed after it was checked": Simple Explanation (and Fix)'](https://blog.angular-university.io/angular-debugging/).
Read more about which solution is right for you in ['Everything you need to know about the "ExpressionChangedAfterItHasBeenCheckedError" error'](https://indepth.dev/posts/1001/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error) and why this is useful at ['Angular Debugging "Expression has changed after it was checked": Simple Explanation (and Fix)'](https://blog.angular-university.io/angular-debugging).
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+17 -3
View File
@@ -4,9 +4,23 @@
@shortDescription Circular dependency in DI detected while instantiating a provider
@description
A cyclic dependency exists when a [dependency of a service](guide/hierarchical-dependency-injection) directly or indirectly depends on the service itself. For example, if `UserService` depends on `EmployeeService`, which also depends on `UserService`. Angular will have to instantiate `EmployeeService` to create `UserService`, which depends on `UserService`, itself.
A cyclic dependency exists when a [dependency of a service](guide/hierarchical-dependency-injection) directly or indirectly depends on the service itself.
For example, if `UserService` depends on `EmployeeService`, which also depends on `UserService`.
Angular will have to instantiate `EmployeeService` to create `UserService`, which depends on `UserService`, itself.
@debugging
Use the call stack to determine where the cyclical dependency exists. You will be able to see if any child dependencies rely on the original file by [mapping out](guide/dependency-injection-in-action) the component, module, or service’s dependencies and identify the loop causing the problem.
Break this loop (or circle) of dependency to resolve this error. This most commonly means removing or refactoring the dependencies to not be reliant on one another.
Use the call stack to determine where the cyclical dependency exists.
You will be able to see if any child dependencies rely on the original file by [mapping out](guide/dependency-injection-in-action) the component, module, or service's dependencies, and identifying the loop causing the problem.
Break this loop \(or circle\) of dependency to resolve this error.
This most commonly means removing or refactoring the dependencies to not be reliant on one another.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+17 -4
View File
@@ -4,17 +4,30 @@
@shortDescription No provider for {token} found!
@description
You see this error when you try to inject a service but have not declared a corresponding provider. A provider is a mapping that supplies a value that you can inject into the constructor of a class in your application.
Read more on providers in our [Dependency Injection guide](guide/dependency-injection).
@debugging
Work backwards from the object where the error states that a [provider](guide/architecture-services) is missing: `No provider for ${this}!`. This is commonly thrown in [services](tutorial/toh-pt4), which require non-existing providers.
Work backwards from the object where the error states that a [provider](guide/architecture-services) is missing: `No provider for ${this}!`.
This is commonly thrown in [services](tutorial/toh-pt4), which require non-existing providers.
To fix the error ensure that your service is registered in the list of providers of an `NgModule` or has the `@Injectable` decorator with a `providedIn` property at top.
The most common solution is to add a provider in `@Injectable` using `providedIn`:
```typescript
@Injectable({ providedIn: 'app' })
```
<code-example format="typescript" language="typescript">
&commat;Injectable({ providedIn: 'app' })
</code-example>
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+16 -6
View File
@@ -7,15 +7,25 @@
Two or more components use the same [element selector](guide/component-overview#specifying-a-components-css-selector). Because there can only be a single component associated with an element, selectors must be unique strings to prevent ambiguity for Angular.
@debugging
Use the element name from the error message to search for places where you’re using the same [selector declaration](guide/architecture-components) in your codebase:
Use the element name from the error message to search for places where you're using the same [selector declaration](guide/architecture-components) in your codebase:
```typescript
@Component({
<code-example format="typescript" language="typescript">
&commat;Component({
selector: 'YOUR_STRING',
...
&hellip;
})
```
</code-example>
Ensure that each component has a unique CSS selector. This will guarantee that Angular renders the component you expect.
If you’re having trouble finding multiple components with this selector tag name, check for components from imported component libraries, such as Angular Material. Make sure you're following the [best practices](guide/styleguide#component-selectors) for your selectors to prevent collisions.
If you're having trouble finding multiple components with this selector tag name, check for components from imported component libraries, such as Angular Material. Make sure you're following the [best practices](guide/styleguide#component-selectors) for your selectors to prevent collisions.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+21 -8
View File
@@ -4,7 +4,10 @@
@shortDescription Export not found!
@description
Angular can’t find a directive with `{{ PLACEHOLDER }}` export name. The export name is specified in the `exportAs` property of the directive decorator. This is common when using FormsModule or Material modules in templates, and you’ve forgotten to [import the corresponding modules](guide/sharing-ngmodules).
Angular can't find a directive with `{{ PLACEHOLDER }}` export name.
The export name is specified in the `exportAs` property of the directive decorator.
This is common when using FormsModule or Material modules in templates and you've forgotten to [import the corresponding modules](guide/sharing-ngmodules).
<div class="alert is-helpful">
@@ -13,20 +16,30 @@ This is the runtime equivalent of a common compiler error [NG8003: No directive
</div>
@debugging
Use the export name to trace the templates or modules using this export.
Ensure that all dependencies are [properly imported and declared in your NgModules](guide/sharing-ngmodules). For example, if the export not found is `ngForm`, we need to import `FormsModule` and declare it in the list of imports in `*.module.ts` to resolve the error.
Ensure that all dependencies are [properly imported and declared in your NgModules](guide/sharing-ngmodules).
For example, if the export not found is `ngForm`, we need to import `FormsModule` and declare it in the list of imports in `*.module.ts` to resolve the error.
```typescript
import { FormsModule } from '@angular/forms';
<code-example format="typescript" language="typescript">
@NgModule({
...
import { FormsModule } from '&commat;angular/forms';
&commat;NgModule({
&hellip;
imports: [
FormsModule,
…
```
&hellip;
</code-example>
If you recently added an import, you may need to restart your server to see these changes.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+15 -4
View File
@@ -4,15 +4,26 @@
@shortDescription Pipe not found!
@description
Angular can't find a pipe with this name.
The pipe referenced in the template has not been named or declared properly.
Angular can't find a pipe with this name.
The pipe referenced in the template has not been named or declared properly.
A [pipe](guide/pipes) must be either declared or imported in the `NgModule` where it is used, and the name used in a template must match the name defined in the pipe decorator.
@debugging
Use the pipe name to trace the templates or modules where this pipe is declared and used.
To resolve this error, ensure that:
- A local custom pipe is uniquely named in the pipe's decorator, and declared in the `NgModule`, or
- A pipe from another `NgModule` is added to the imports of the `NgModule` where it is used.
* A local custom pipe is uniquely named in the pipe's decorator, and declared in the `NgModule`, or
* A pipe from another `NgModule` is added to the imports of the `NgModule` where it is used
If you recently added an import or declaration, you may need to restart your server to see these changes.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+23 -8
View File
@@ -3,27 +3,42 @@
@shortDescription Decorator argument is not an object literal
@description
To make the metadata extraction in the Angular compiler faster, the decorators `@NgModule`, `@Pipe`, `@Component`, `@Directive`, and `@Injectable` accept only object literals as arguments.
This is an [intentional change in Ivy](https://github.com/angular/angular/issues/30840#issuecomment-498869540), which enforces stricter argument requirements for decorators than View Engine. Ivy requires this approach because it compiles decorators by moving the expressions into other locations in the class output.
This is an [intentional change in Ivy](https://github.com/angular/angular/issues/30840#issuecomment-498869540), which enforces stricter argument requirements for decorators than View Engine.
Ivy requires this approach because it compiles decorators by moving the expressions into other locations in the class output.
@debugging
Move all declarations:
```typescript
const moduleDefinition = {...}
<code-example format="typescript" language="typescript">
@NgModule(moduleDefinition)
const moduleDefinition = {&hellip;}
&commat;NgModule(moduleDefinition)
export class AppModule {
constructor() {}
}
```
</code-example>
into the decorator:
```typescript
@NgModule({...})
<code-example format="typescript" language="typescript">
&commat;NgModule({&hellip;})
export class AppModule {
constructor() {}
}
```
</code-example>
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+14 -2
View File
@@ -3,9 +3,21 @@
@shortDescription No suitable injection token for parameter
@description
There is no injection token for a constructor parameter at compile time. [InjectionTokens](api/core/InjectionToken) are tokens that can be used in a Dependency Injection Provider.
@debugging
Look at the parameter that throws the error and all uses of the class. This error is commonly thrown when a constructor defines parameters with primitive types like `string`, `number`, `boolean`, and `Object`.
Use the `@Injectable` method or `@Inject` decorator from `@angular/core` to ensure that the type you are injecting is reified (has a runtime representation). Make sure to add a provider to this decorator so that you do not throw [NG0201: No Provider Found](errors/NG0201).
Look at the parameter that throws the error, and all uses of the class.
This error is commonly thrown when a constructor defines parameters with primitive types such as `string`, `number`, `boolean`, and `Object`.
Use the `@Injectable` method or `@Inject` decorator from `@angular/core` to ensure that the type you are injecting is reified \(has a runtime representation\).
Make sure to add a provider to this decorator so that you do not throw [NG0201: No Provider Found](errors/NG0201).
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+20 -11
View File
@@ -3,30 +3,39 @@
@shortDescription Component selector does not match shadow DOM requirements
@description
The selector of a component using `ViewEncapsulation.ShadowDom` doesn't match the custom element tag name requirements.
In order for a tag name to be considered a valid custom element name, it has to:
* Be in lower case.
* Contain a hyphen.
* Start with a letter (a-z).
* Be in lower case.
* Contain a hyphen.
* Start with a letter \(a-z\).
@debugging
Rename your component's selector so that it matches the requirements.
**Before:**
```typescript
@Component({
<code-example format="typescript" language="typescript">
&commat;Component({
selector: 'comp',
encapsulation: ViewEncapsulation.ShadowDom
...
&hellip;
})
```
</code-example>
**After:**
```typescript
@Component({
<code-example format="typescript" language="typescript">
&commat;Component({
selector: 'app-comp',
encapsulation: ViewEncapsulation.ShadowDom
...
&hellip;
})
```
</code-example>
+37 -32
View File
@@ -4,54 +4,59 @@
@description
A component, directive or pipe that is referenced by this component would require the compiler
to add an import that would lead to a cycle of imports. For example, consider a scenario where
a `ParentComponent` references a `ChildComponent` in its template:
A component, directive, or pipe that is referenced by this component would require the compiler to add an import that would lead to a cycle of imports.
For example, consider a scenario where a `ParentComponent` references a `ChildComponent` in its template:
<code-example path="errors/cyclic-imports/parent.component.ts" header="parent.component.ts"></code-example>
<code-example header="parent.component.ts" path="errors/cyclic-imports/parent.component.ts"></code-example>
<code-example path="errors/cyclic-imports/child.component.ts" header="child.component.ts"></code-example>
<code-example header="child.component.ts" path="errors/cyclic-imports/child.component.ts"></code-example>
There is already an import from `child.component.ts` to `parent.component.ts` since the `ChildComponent`
references the `ParentComponent` in its constructor.
There is already an import from `child.component.ts` to `parent.component.ts` since the `ChildComponent` references the `ParentComponent` in its constructor.
But note that the parent component's template contains `<child></child>`. The generated code for this
template must therefore contain a reference to the `ChildComponent` class. In order to make this reference
the compiler would have to add an import from `parent.component.ts` to `child.component.ts`, which would
cause an import cycle:
<div class="alert is-helpful">
```
parent.component.ts -> child.component.ts -> parent.component.ts
```
**NOTE**: <br />
The parent component's template contains `<child></child>`.
The generated code for this template must therefore contain a reference to the `ChildComponent` class.
In order to make this reference, the compiler would have to add an import from `parent.component.ts` to `child.component.ts`, which would cause an import cycle:
<code-example format="none" language="none">
parent.component.ts -&gt; child.component.ts -&gt; parent.component.ts
</code-example>
</div>
### Remote Scoping
To avoid adding imports that create cycles, additional code is added to the `NgModule` class where
the component is declared that wires up the dependencies. This is known as "remote scoping".
To avoid adding imports that create cycles, additional code is added to the `NgModule` class where the component that wires up the dependencies is declared.
This is known as "remote scoping".
### Libraries
Unfortunately, "remote scoping" code is side-effectful, which prevents tree shaking, and cannot
be used in libraries. So when building libraries using the `"compilationMode": "partial"` setting,
any component that would require a cyclic import will cause this `NG3003` compiler error to be raised.
Unfortunately, "remote scoping" code is side-effectful &mdash;which prevents tree shaking&mdash; and cannot be used in libraries.
So when building libraries using the `"compilationMode": "partial"` setting, any component that would require a cyclic import will cause this `NG3003` compiler error to be raised.
@debugging
The cycle that would be generated is shown as part of the error message. For example:
The cycle that would be generated is shown as part of the error message.
For example:
<code-example hideCopy="true">
<span class="nocode">The component ChildComponent is used in the template but importing it would create a cycle:
/parent.component.ts -> /child.component.ts -> /parent.component.ts</span>
The component ChildComponent is used in the template but importing it would create a cycle:
/parent.component.ts -&gt; /child.component.ts -&gt; /parent.component.ts
</code-example>
Use this to identify how the referenced component, pipe or directive has a dependency back to the
component being compiled. Here are some ideas for fixing the problem:
Use this to identify how the referenced component, pipe, or directive has a dependency back to the component being compiled.
Here are some ideas for fixing the problem:
* Try to re-arrange your dependencies to avoid the cycle. For example using an intermediate interface
that is stored in an independent file that can be imported to both dependent files without
causing an import cycle.
* Move the classes that reference each other into the same file, to avoid any imports between them.
* Convert import statements to type-only imports (using `import type` syntax) if the imported declarations
are only used as types, as type-only imports do not contribute to cycles.
* Try to rearrange your dependencies to avoid the cycle.
For example, using an intermediate interface that is stored in an independent file that can be imported to both dependent files without causing an import cycle.
* Move the classes that reference each other into the same file, to avoid any imports between them.
* Convert import statements to type-only imports \(using `import type` syntax\) if the imported declarations are only used as types, as type-only imports do not contribute to cycles.
@reviewed 2022-02-28
+2
View File
@@ -3,9 +3,11 @@
@shortDescription Invalid @NgModule() metadata
@description
This error represents the import or export of an `@NgModule()` that doesn't have valid metadata.
@debugging
The library might have been processed with `ngcc`.
If this is the case, try removing and reinstalling `node_modules`.
This error is likely due to the library being published for Angular Ivy, which cannot be used in this View Engine application.
+13 -2
View File
@@ -3,19 +3,30 @@
@shortDescription Unknown HTML element or component
@description
One or more elements cannot be resolved during compilation because the element is not defined by the HTML spec, or there is no component or directive with such element selector.
<div class="alert is-helpful">
This is the compiler equivalent of a common runtime error `NG0304: '${tagName}' is not a known element: …`.
This is the compiler equivalent of a common runtime error `NG0304: '${tagName}' is not a known element: &hellip;`.
</div>
@debugging
Use the element name in the error to find the file(s) where the element is being used.
Check that the name and selector are correct. If the component is from a different module or import, check that the component is exported from its origin module and imported into the correct `*.modules.ts` file, and declared in the imports list.
Check that the name and selector are correct.
If the component is from a different module or import, check that the component is exported from its origin module and imported into the correct `*.modules.ts` file, and declared in the imports list.
When using custom elements or web components, ensure that you add [`CUSTOM_ELEMENTS_SCHEMA`](api/core/CUSTOM_ELEMENTS_SCHEMA) to the application module.
If this does not resolve the error, check the imported libraries for any recent changes to the exports and properties you are using, and restart your server.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+19 -5
View File
@@ -4,13 +4,27 @@
@shortDescription Unknown attribute or input
@description
An attribute or property cannot be resolved during compilation.
This error arises when attempting to bind to a property that does not exist. Any property binding must correspond to either:
* A native property on the HTML element, or
* An `@Input()` property of a component or directive applied to the element.
This error arises when attempting to bind to a property that does not exist.
Any property binding must correspond to either:
The runtime error for this is `NG0304: '${tagName}' is not a known element: …’`.
* A native property on the HTML element, or
* An `@Input()` property of a component or directive applied to the element.
The runtime error for this is `NG0304: '${tagName}' is not a known element: &hellip;'`.
@debugging
Look at documentation for the specific [binding syntax](guide/binding-syntax) used. This is usually a typo or incorrect import. There may also be a missing direction with property selector ‘name’ or missing input.
Look at documentation for the specific [binding syntax](guide/binding-syntax) used.
This is usually a typo or incorrect import.
There may also be a missing direction with property selector 'name' or missing input.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+21 -8
View File
@@ -4,8 +4,9 @@
@shortDescription No directive found with export
@description
Angular can’t find a directive with `{{ PLACEHOLDER }}` export name. This is common with a missing import or a missing [`exportAs`](api/core/Directive#exportAs) on a directive.
Angular can't find a directive with `{{ PLACEHOLDER }}` export name.
This is common with a missing import or a missing [`exportAs`](api/core/Directive#exportAs) on a directive.
<div class="alert is-helpful">
@@ -14,18 +15,30 @@ This is the compiler equivalent of a common runtime error [NG0301: Export Not Fo
</div>
@debugging
Use the string name of the export not found to trace the templates or modules using this export.
Ensure that all dependencies are properly imported and declared in our Modules. For example, if the export not found is `ngForm`, we will need to import `FormsModule` and declare it in our list of imports in `*.module.ts` to resolve the missing export error.
Ensure that all dependencies are properly imported and declared in our Modules.
For example, if the export not found is `ngForm`, we will need to import `FormsModule` and declare it in our list of imports in `*.module.ts` to resolve the missing export error.
```typescript
import { FormsModule } from '@angular/forms';
<code-example format="typescript" language="typescript">
@NgModule({
...
import { FormsModule } from '&commat;angular/forms';
&commat;NgModule({
&hellip;
imports: [
FormsModule,
…
```
&hellip;
</code-example>
If you recently added an import, you will need to restart your server to see these changes.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
@@ -1,4 +1,4 @@
// #docplaster ...
// #docplaster &hellip;
// #docregion webpack-config
import linkerPlugin from '@angular/compiler-cli/linker/babel';
@@ -8,8 +8,11 @@ import * as auto from './auto.po';
import * as filterStagger from './filter-stagger.po';
import * as heroGroups from './hero-groups';
import { getLinkById, sleepFor } from './util';
import { getComponentSection, getToggleButton } from './querying.po';
describe('Animation Tests', () => {
const routingAnimationDuration = 350;
const openCloseHref = getLinkById('open-close');
const statusSliderHref = getLinkById('status');
const toggleHref = getLinkById('toggle');
@@ -17,6 +20,9 @@ describe('Animation Tests', () => {
const autoHref = getLinkById('auto');
const filterHref = getLinkById('heroes');
const heroGroupsHref = getLinkById('hero-groups');
const queryingHref = getLinkById('querying');
const newPageSleepFor = (ms = 0) => sleepFor(ms + routingAnimationDuration);
beforeAll(() => browser.get(''));
@@ -26,7 +32,7 @@ describe('Animation Tests', () => {
beforeAll(async () => {
await openCloseHref.click();
await sleepFor();
await newPageSleepFor(300);
});
it('should be open', async () => {
@@ -82,7 +88,7 @@ describe('Animation Tests', () => {
beforeAll(async () => {
await statusSliderHref.click();
await sleepFor(2000);
await newPageSleepFor(2000);
});
it('should be inactive with a blue background', async () => {
@@ -123,7 +129,7 @@ describe('Animation Tests', () => {
describe('Toggle Animations Component', () => {
beforeAll(async () => {
await toggleHref.click();
await sleepFor();
await newPageSleepFor();
});
it('should disabled animations on the child element', async () => {
@@ -141,7 +147,7 @@ describe('Animation Tests', () => {
describe('Enter/Leave Component', () => {
beforeAll(async () => {
await enterLeaveHref.click();
await sleepFor(100);
await newPageSleepFor(100);
});
it('should attach a flyInOut trigger to the list of items', async () => {
@@ -167,7 +173,7 @@ describe('Animation Tests', () => {
describe('Auto Calculation Component', () => {
beforeAll(async () => {
await autoHref.click();
await sleepFor(0);
await newPageSleepFor();
});
it('should attach a shrinkOut trigger to the list of items', async () => {
@@ -191,7 +197,7 @@ describe('Animation Tests', () => {
describe('Filter/Stagger Component', () => {
beforeAll(async () => {
await filterHref.click();
await sleepFor();
await newPageSleepFor();
});
it('should attach a filterAnimations trigger to the list container', async () => {
@@ -218,7 +224,7 @@ describe('Animation Tests', () => {
describe('Hero Groups Component', () => {
beforeAll(async () => {
await heroGroupsHref.click();
await sleepFor(300);
await newPageSleepFor(400);
});
it('should attach a flyInOut trigger to the list of items', async () => {
@@ -242,4 +248,49 @@ describe('Animation Tests', () => {
await browser.wait(async () => await heroesList.count() < total, 2000);
});
});
describe('Querying Component', () => {
const queryingAnimationDuration = 2500;
beforeAll(async () => {
await queryingHref.click();
await newPageSleepFor(queryingAnimationDuration);
});
it('should toggle the section', async () => {
const toggleButton = getToggleButton();
const section = getComponentSection();
expect(await section.isPresent()).toBe(true);
// toggling off
await toggleButton.click();
await newPageSleepFor(queryingAnimationDuration);
expect(await section.isPresent()).toBe(false);
// toggling on
await toggleButton.click();
await newPageSleepFor(queryingAnimationDuration);
expect(await section.isPresent()).toBe(true);
await newPageSleepFor(queryingAnimationDuration);
});
it(`should disable the button for the animation's duration`, async () => {
const toggleButton = getToggleButton();
expect(await toggleButton.isEnabled()).toBe(true);
// toggling off
await toggleButton.click();
expect(await toggleButton.isEnabled()).toBe(false);
await newPageSleepFor(queryingAnimationDuration);
expect(await toggleButton.isEnabled()).toBe(true);
// toggling on
await toggleButton.click();
expect(await toggleButton.isEnabled()).toBe(false);
await newPageSleepFor(queryingAnimationDuration);
expect(await toggleButton.isEnabled()).toBe(true);
});
});
});
@@ -0,0 +1,16 @@
import { by } from 'protractor';
import { locate } from './util';
export function getComponent() {
return by.css('app-querying');
}
export function getToggleButton() {
const toggleButton = () => by.className('toggle');
return locate(getComponent(), toggleButton());
}
export function getComponentSection() {
const findSection = () => by.css('section');
return locate(getComponent(), findSection());
}
@@ -39,11 +39,10 @@ export const slideInAnimation =
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
])
]),
]),
query(':enter', animateChild()),
]),
transition('* <=> FilterPage', [
transition('* <=> *', [
style({ position: 'relative' }),
query(':enter, :leave', [
style({
@@ -59,13 +58,13 @@ export const slideInAnimation =
query(':leave', animateChild()),
group([
query(':leave', [
animate('200ms ease-out', style({ left: '100%' }))
animate('200ms ease-out', style({ left: '100%', opacity: 0 }))
]),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
])
]),
query('@*', animateChild())
]),
query(':enter', animateChild()),
])
// #enddocregion query
]);
@@ -1,3 +1,15 @@
nav a {
padding: .7rem;
}
h1 {
margin-bottom: .3rem;
}
form {
margin-bottom: 2rem;
}
nav {
padding-bottom: 3rem;
}
@@ -17,11 +17,11 @@
<a id="heroes" routerLink="/heroes" routerLinkActive="active">Filter/Stagger</a>
<a id="hero-groups" routerLink="/hero-groups" routerLinkActive="active">Hero Groups</a>
<a id="insert-remove" routerLink="/insert-remove" routerLinkActive="active">Insert/Remove</a>
<a id="querying" routerLink="/querying" routerLinkActive="active">Querying</a>
</nav>
<!-- #docregion route-animations-outlet -->
<div [@routeAnimations]="prepareRoute(outlet)">
<router-outlet #outlet="outlet"></router-outlet>
<div [@routeAnimations]="getRouteAnimationData()">
<router-outlet></router-outlet>
</div>
<!-- #enddocregion route-animations-outlet -->
@@ -11,7 +11,7 @@ import {
} from '@angular/animations';
// #enddocregion imports
import { RouterOutlet } from '@angular/router';
import { ChildrenOutletContexts, RouterOutlet } from '@angular/router';
import { slideInAnimation } from './animations';
// #docregion decorator, toggle-app-animations, define
@@ -34,12 +34,13 @@ export class AppComponent {
public animationsDisabled = false;
// #enddocregion toggle-app-animations
// #docregion prepare-router-outlet
prepareRoute(outlet: RouterOutlet) {
return outlet?.activatedRouteData?.['animation'];
}
// #docregion get-route-animations-data
constructor(private contexts: ChildrenOutletContexts) {}
// #enddocregion prepare-router-outlet
getRouteAnimationData() {
return this.contexts.getContext('primary')?.route?.snapshot?.data?.['animation'];
}
// #enddocregion get-route-animations-data
toggleAnimations() {
this.animationsDisabled = !this.animationsDisabled;
@@ -20,6 +20,7 @@ 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';
@NgModule({
@@ -28,17 +29,61 @@ import { InsertRemoveComponent } from './insert-remove.component';
BrowserAnimationsModule,
RouterModule.forRoot([
{ path: '', pathMatch: 'full', redirectTo: '/enter-leave' },
{ path: 'open-close', component: OpenClosePageComponent },
{ path: 'status', component: StatusSliderPageComponent },
{ path: 'toggle', component: ToggleAnimationsPageComponent },
{ path: 'heroes', component: HeroListPageComponent,
data: { animation: 'FilterPage' } },
{ path: 'hero-groups', component: HeroListGroupPageComponent },
{ path: 'enter-leave', component: HeroListEnterLeavePageComponent },
{ path: 'auto', component: HeroListAutoCalcPageComponent },
{ path: 'insert-remove', component: InsertRemoveComponent},
{ path: 'home', component: HomeComponent, data: { animation: 'HomePage' } },
{ path: 'about', component: AboutComponent, data: { animation: 'AboutPage' } },
{
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
@@ -59,6 +104,7 @@ import { InsertRemoveComponent } from './insert-remove.component';
HeroListAutoComponent,
HomeComponent,
InsertRemoveComponent,
QueryingComponent,
AboutComponent
],
bootstrap: [AppComponent]
@@ -0,0 +1,31 @@
section {
border: 1px solid black;
overflow: hidden;
}
section > * {
margin: 1rem;
}
.hero {
display: flex;
align-items: center;
border-radius: 4px;
color: black;
background-color: #DDD;
}
.hero .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.5rem;
background-color: #3d5157;
margin-right: .8em;
border-radius: 4px 0 0 4px;
align-self: stretch;
}
.hero .name {
height: min-content;
}
@@ -0,0 +1,80 @@
import {
Component,
} from '@angular/core';
import {
trigger,
style,
animate,
transition,
group,
query,
animateChild,
keyframes
} from '@angular/animations';
import { HEROES } from './mock-heroes';
@Component({
selector: 'app-querying',
template: `
<nav>
<button class="toggle" (click)="show = !show" [disabled]="toggleDisabled">Toggle View</button>
</nav>
<section *ngIf="show" @query (@query.start)="toggleDisabled = true" (@query.done)="toggleDisabled = false">
<p>I am a simple child element</p>
<p *ngIf="show">I am a child element that enters and leaves with its parent</p>
<p @animateMe>I am a child element with an animation trigger</p>
<div class="hero">
<span class="badge">{{ hero.id }}</span>
<span class="name">{{ hero.name }} <small>(heroes are always animated!)</small></span>
</div>
</section>
`,
styleUrls: ['./querying.component.css'],
animations: [
trigger('query', [
transition(':enter', [
style({ height: 0 }),
group([
animate(500, style({ height: '*' })),
query(':enter', [
style({ opacity: 0, transform: 'scale(0)'}),
animate(2000, style({ opacity: 1, transform: 'scale(1)' }))
]),
query('.hero', [
style({ transform: 'translateX(-100%)'}),
animate('.7s 500ms ease-in', style({ transform: 'translateX(0)' }))
]),
]),
query('@animateMe', animateChild()),
]),
transition(':leave', [
style({ height: '*' }),
query('@animateMe', animateChild()),
group([
animate('500ms 500ms', style({ height: '0', padding: '0' })),
query(':leave', [
style({ opacity: 1, transform: 'scale(1)'}),
animate('1s', style({ opacity: 0, transform: 'scale(0)' }))
]),
query('.hero', [
style({ transform: 'translateX(0)'}),
animate('.7s ease-out', style({ transform: 'translateX(-100%)' }))
]),
]),
]),
]),
trigger('animateMe', [
transition('* <=> *', animate('500ms cubic-bezier(.68,-0.73,.26,1.65)', keyframes([
style({ backgroundColor: "transparent", color: '*', offset: 0 }),
style({ backgroundColor: "blue", color: 'white', offset: 0.2 }),
style({ backgroundColor: "transparent", color: '*', offset: 1 })
])))
]),
]
})
export class QueryingComponent {
toggleDisabled = false;
show = true;
hero = HEROES[0];
}
@@ -25,7 +25,6 @@
background-color: #EEE;
margin: .5em;
padding: 0;
height: 1.6em;
border-radius: 4px;
display: flex;
align-items: stretch;
@@ -1,5 +1,5 @@
// #docregion
import { Component, Input, OnDestroy, AfterViewInit, ViewChild } from '@angular/core';
import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { AdDirective } from './ad.directive';
import { AdItem } from './ad-item';
@@ -17,7 +17,7 @@ import { AdComponent } from './ad.component';
// #enddocregion ad-host
})
// #docregion class
export class AdBannerComponent implements AfterViewInit, OnDestroy {
export class AdBannerComponent implements OnInit, OnDestroy {
@Input() ads: AdItem[] = [];
currentAdIndex = -1;
@@ -25,7 +25,7 @@ export class AdBannerComponent implements AfterViewInit, OnDestroy {
@ViewChild(AdDirective, {static: true}) adHost!: AdDirective;
interval: number|undefined;
ngAfterViewInit() {
ngOnInit(): void {
this.loadComponent();
this.getAds();
}
@@ -0,0 +1,16 @@
.checkboxes {
display: flex;
flex-wrap: wrap;
margin-bottom: 2rem;
}
.checkboxes > label {
flex: 0 0 max-content;
margin: 0.5rem;
cursor: pointer;
}
section:not(:last-of-type) {
padding-bottom: 2rem;
border-bottom: 1px solid black;
}
@@ -1,29 +1,46 @@
<h1>HttpClient Example</h1>
<div>
<input type="checkbox" id="heroes" [checked]="showHeroes" (click)="toggleHeroes()">
<label for="heroes">Heroes</label>
<div class="checkboxes">
<label>
<input type="checkbox" [checked]="showHeroes" (click)="toggleHeroes()">
Heroes
</label>
<input type="checkbox" id="config" [checked]="showConfig" (click)="toggleConfig()">
<label for="config">Config</label>
<label>
<input type="checkbox" [checked]="showConfig" (click)="toggleConfig()">
Config
</label>
<input type="checkbox" id="downloader" [checked]="showDownloader" (click)="toggleDownloader()">
<label for="downloader">Downloader</label>
<label>
<input type="checkbox" [checked]="showDownloader" (click)="toggleDownloader()">
Downloader
</label>
<input type="checkbox" id="uploader" [checked]="showUploader" (click)="toggleUploader()">
<label for="uploader">Uploader</label>
<label>
<input type="checkbox" [checked]="showUploader" (click)="toggleUploader()">
Uploader
</label>
<input type="checkbox" id="search" [checked]="showSearch" (click)="toggleSearch()">
<label for="search">Search</label>
<label>
<input type="checkbox" id="search" [checked]="showSearch" (click)="toggleSearch()">
Search
</label>
</div>
<app-heroes *ngIf="showHeroes"></app-heroes>
<hr />
<app-messages></app-messages>
<hr />
<app-config *ngIf="showConfig"></app-config>
<hr />
<app-downloader *ngIf="showDownloader"></app-downloader>
<hr />
<app-uploader *ngIf="showUploader"></app-uploader>
<hr />
<app-package-search *ngIf="showSearch"></app-package-search>
<section>
<app-messages></app-messages>
</section>
<section *ngIf="showHeroes">
<app-heroes></app-heroes>
</section>
<section *ngIf="showConfig">
<app-config></app-config>
</section>
<section *ngIf="showDownloader">
<app-downloader></app-downloader>
</section>
<section *ngIf="showUploader">
<app-uploader></app-uploader>
</section>
<section *ngIf="showSearch">
<app-package-search></app-package-search>
</section>
@@ -2,7 +2,8 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
showHeroes = true;
@@ -16,4 +17,4 @@ export class AppComponent {
toggleDownloader() { this.showDownloader = !this.showDownloader; }
toggleUploader() { this.showUploader = !this.showUploader; }
toggleSearch() { this.showSearch = !this.showSearch; }
}
}
@@ -28,10 +28,10 @@ export class ConfigComponent {
showConfig() {
this.configService.getConfig()
// #enddocregion v1, v2
.subscribe(
(data: Config) => this.config = { ...data }, // success path
error => this.error = error // error path
);
.subscribe({
next: (data: Config) => this.config = { ...data }, // success path
error: error => this.error = error, // error path
});
}
showConfig_v1() {
@@ -69,7 +69,7 @@ export class ConfigComponent {
}
// #enddocregion showConfigResponse
makeError() {
this.configService.makeIntentionalError().subscribe(null, error => this.error = error );
this.configService.makeIntentionalError().subscribe({ error: error => this.error = error.message });
}
getType(val: any): string {
@@ -82,8 +82,7 @@ export class ConfigService {
`Backend returned code ${error.status}, body was: `, error.error);
}
// Return an observable with a user-facing error message.
return throwError(
'Something bad happened; please try again later.');
return throwError(() => new Error('Something bad happened; please try again later.'));
}
// #enddocregion handleError
@@ -9,57 +9,71 @@
}
.heroes li {
display: flex;
width: 100%;
}
.heroes li:hover {
left: .1em;
}
.heroes button.delete {
color: black;
display: block;
font-size: 1.2rem;
display: grid;
grid-template-columns: min-content max-content 1fr max-content max-content;
grid-template-areas: "badge name . edit delete";
margin: 1rem 0;
align-items: center;
background-color: #eee;
border-radius: 0 4px 4px 0;
border-radius: 4px;
}
.heroes a:hover {
color: #2c3a41;
background-color: #e6e6e6;
.heroes li .badge {
grid-area: badge;
}
.heroes li .name {
grid-area: name;
}
.heroes li button {
margin: 0.3rem;
padding: 0.3rem 0.8rem;
}
.heroes li button.edit {
grid-area: edit;
}
.heroes li button.delete {
grid-area: delete;
}
.heroes li button:hover, .heros li button:focus {
color: #eee;
background-color: #000;
}
.heroes .badge {
padding: .5em .6em;
padding: 0.5rem 0.6rem;
color: white;
background-color: #435B60;
min-width: 16px;
margin-right: .8em;
margin-right: 0.8rem;
border-radius: 4px 0 0 4px;
}
.heroes button.edit {
flex: 1;
text-align: left;
padding: 0;
margin-right: 0;
align-self: stretch;
display: flex;
align-items: center;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
button.delete {
right: -8px;
top: 5px;
background-color: gray;
color: white;
padding: 5px 8px;
width: 2em;
}
.heroes input {
max-width: 12rem;
padding: .25rem;
}
@media (max-width: 550px) {
.heroes li {
grid-template-columns: min-content 1fr 1fr;
grid-template-rows: 2rem max-content;
grid-template-areas:
"badge name name"
"badge edit delete";
}
.heroes li .name {
margin-top: 0.3rem;
}
.heroes li button {
justify-self: center;
}
}
@@ -1,29 +1,29 @@
<h2>Heroes</h2>
<div class="search">
<label for="hero-name">Hero name: </label>
<input type="text" #heroName id="hero-name">
<input type="text" [(ngModel)]="heroName" id="hero-name">
<!-- (click) passes input value to add() and then clears the input -->
<button type="button" (click)="add(heroName.value); heroName.value=''">
Add hero
</button>
<button type="button" (click)="search(heroName.value)">
<button type="button" [disabled]="!heroName"
(click)="add(heroName)">Add hero</button>
<button type="button" (click)="search(heroName)">
Search
</button>
</div>
<ul class="heroes">
<li *ngFor="let hero of heroes">
<button type="button" class="edit" (click)="edit(hero)">
<span class="badge">{{ hero.id || -1 }}</span>
<span *ngIf="hero!==editHero">{{hero.name}}</span>
<input type="text"
*ngIf="hero===editHero"
[(ngModel)]="hero.name"
(blur)="update()"
(keyup.enter)="update()">
<span class="badge">{{ hero.id || -1 }}</span>
<span *ngIf="hero!==editHero; else editInput" class="name">{{hero.name}}</span>
<ng-template #editInput>
<input #heroEditInput type="text" class="name" [value]="editHero!.name" (blur)="edit(heroEditInput.value)" (keydown.enter)="edit(heroEditInput.value)"/>
</ng-template>
<button *ngIf="hero!==editHero" type="button" class="edit" title="edit hero"
(click)="editHero = hero">
Edit
</button>
<button type="button" class="delete" title="delete hero"
(click)="delete(hero)">x</button>
(click)="delete(hero)">
Delete
</button>
</li>
</ul>
@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { Hero } from './hero';
import { HeroesService } from './heroes.service';
@@ -12,9 +12,17 @@ import { HeroesService } from './heroes.service';
export class HeroesComponent implements OnInit {
heroes: Hero[] = [];
editHero: Hero | undefined; // the hero currently being edited
heroName = '';
constructor(private heroesService: HeroesService) {}
@ViewChild('heroEditInput')
set heroEditInput(element: ElementRef<HTMLInputElement>) {
if (element) {
element.nativeElement.focus();
}
}
ngOnInit() {
this.getHeroes();
}
@@ -55,8 +63,9 @@ export class HeroesComponent implements OnInit {
*/
}
edit(hero: Hero) {
this.editHero = hero;
edit(heroName: string) {
this.update(heroName);
this.editHero = undefined;
}
search(searchTerm: string) {
@@ -65,13 +74,15 @@ export class HeroesComponent implements OnInit {
this.heroesService
.searchHeroes(searchTerm)
.subscribe(heroes => (this.heroes = heroes));
} else {
this.getHeroes();
}
}
update() {
if (this.editHero) {
update(heroName: string) {
if (heroName && this.editHero && this.editHero.name !== heroName) {
this.heroesService
.updateHero(this.editHero)
.updateHero({...this.editHero, name: heroName})
.subscribe(hero => {
// replace the hero in the heroes list with update from server
const ix = hero ? this.heroes.findIndex(h => h.id === hero.id) : -1;
@@ -53,10 +53,10 @@ describe('HeroesService', () => {
it('should return expected heroes (called once)', () => {
heroService.getHeroes().subscribe(
heroes => expect(heroes).toEqual(expectedHeroes, 'should return expected heroes'),
fail
);
heroService.getHeroes().subscribe({
next: heroes => expect(heroes).toEqual(expectedHeroes, 'should return expected heroes'),
error: fail,
});
// HeroService should have made one request to GET heroes from expected URL
const req = httpTestingController.expectOne(heroService.heroesUrl);
@@ -68,10 +68,10 @@ describe('HeroesService', () => {
it('should be OK returning no heroes', () => {
heroService.getHeroes().subscribe(
heroes => expect(heroes.length).toEqual(0, 'should have empty heroes array'),
fail
);
heroService.getHeroes().subscribe({
next: heroes => expect(heroes.length).toEqual(0, 'should have empty heroes array'),
error: fail,
});
const req = httpTestingController.expectOne(heroService.heroesUrl);
req.flush([]); // Respond with no heroes
@@ -80,10 +80,10 @@ describe('HeroesService', () => {
// This service reports the error but finds a way to let the app keep going.
it('should turn 404 into an empty heroes result', () => {
heroService.getHeroes().subscribe(
heroes => expect(heroes.length).toEqual(0, 'should return empty heroes array'),
fail
);
heroService.getHeroes().subscribe({
next: heroes => expect(heroes.length).toEqual(0, 'should return empty heroes array'),
error: fail,
});
const req = httpTestingController.expectOne(heroService.heroesUrl);
@@ -96,10 +96,10 @@ describe('HeroesService', () => {
heroService.getHeroes().subscribe();
heroService.getHeroes().subscribe();
heroService.getHeroes().subscribe(
heroes => expect(heroes).toEqual(expectedHeroes, 'should return expected heroes'),
fail
);
heroService.getHeroes().subscribe({
next: heroes => expect(heroes).toEqual(expectedHeroes, 'should return expected heroes'),
error: fail,
});
const requests = httpTestingController.match(heroService.heroesUrl);
expect(requests.length).toEqual(3, 'calls to getHeroes()');
@@ -119,10 +119,10 @@ describe('HeroesService', () => {
const updateHero: Hero = { id: 1, name: 'A' };
heroService.updateHero(updateHero).subscribe(
data => expect(data).toEqual(updateHero, 'should return the hero'),
fail
);
heroService.updateHero(updateHero).subscribe({
next: data => expect(data).toEqual(updateHero, 'should return the hero'),
error: fail,
});
// HeroService should have made one request to PUT hero
const req = httpTestingController.expectOne(heroService.heroesUrl);
@@ -139,10 +139,10 @@ describe('HeroesService', () => {
it('should turn 404 error into return of the update hero', () => {
const updateHero: Hero = { id: 1, name: 'A' };
heroService.updateHero(updateHero).subscribe(
data => expect(data).toEqual(updateHero, 'should return the update hero'),
fail
);
heroService.updateHero(updateHero).subscribe({
next: data => expect(data).toEqual(updateHero, 'should return the update hero'),
error: fail,
});
const req = httpTestingController.expectOne(heroService.heroesUrl);
@@ -0,0 +1,9 @@
:host {
display: block;
padding: 1rem;
background-color: rgb(255, 245, 187);
}
h2 {
margin: 0;
}
@@ -1,8 +1,8 @@
<div *ngIf="messageService.messages.length">
<h2>Messages</h2>
<h2>Messages</h2>
<ng-container *ngIf="messageService.messages.length">
<button type="button" class="clear" (click)="messageService.clear()">clear</button>
<br>
<ol>
<li *ngFor='let message of messageService.messages'> {{message}} </li>
</ol>
</div>
</ng-container>
@@ -3,7 +3,8 @@ import { MessageService } from '../message.service';
@Component({
selector: 'app-messages',
templateUrl: './messages.component.html'
templateUrl: './messages.component.html',
styleUrls: ['./messages.component.css']
})
export class MessagesComponent {
constructor(public messageService: MessageService) {}
@@ -97,13 +97,13 @@ describe('HttpClient testing', () => {
// Make three requests in a row
httpClient.get<Data[]>(testUrl)
.subscribe(d => expect(d.length).toEqual(0, 'should have no data'));
.subscribe(d => expect(d.length).withContext('should have no data').toEqual(0));
httpClient.get<Data[]>(testUrl)
.subscribe(d => expect(d).toEqual([testData[0]], 'should be one element array'));
.subscribe(d => expect(d).withContext('should be one element array').toEqual([testData[0]]));
httpClient.get<Data[]>(testUrl)
.subscribe(d => expect(d).toEqual(testData, 'should be expected data'));
.subscribe(d => expect(d).withContext('should be expected data').toEqual(testData));
// #docregion multi-request
// get all pending requests that match the given URL
@@ -121,13 +121,13 @@ describe('HttpClient testing', () => {
it('can test for 404 error', () => {
const emsg = 'deliberate 404 error';
httpClient.get<Data[]>(testUrl).subscribe(
data => fail('should have failed with the 404 error'),
(error: HttpErrorResponse) => {
expect(error.status).toEqual(404, 'status');
expect(error.error).toEqual(emsg, 'message');
}
);
httpClient.get<Data[]>(testUrl).subscribe({
next: () => fail('should have failed with the 404 error'),
error: (error: HttpErrorResponse) => {
expect(error.status).withContext('status').toEqual(404);
expect(error.error).withContext('message').toEqual(emsg);
},
});
const req = httpTestingController.expectOne(testUrl);
@@ -142,13 +142,13 @@ describe('HttpClient testing', () => {
// at network level. e.g. Connection timeout, DNS error, offline, etc.
const mockError = new ProgressEvent('error');
httpClient.get<Data[]>(testUrl).subscribe(
data => fail('should have failed with the network error'),
(error: HttpErrorResponse) => {
httpClient.get<Data[]>(testUrl).subscribe({
next: () => fail('should have failed with the network error'),
error: (error: HttpErrorResponse) => {
expect(error.error).toBe(mockError);
done();
}
);
},
});
const req = httpTestingController.expectOne(testUrl);
+13 -22
View File
@@ -20,10 +20,12 @@
"i18n": {
"sourceLocale": "en-US",
"locales": {
"fr": "src/locale/messages.fr.xlf",
// #enddocregion locale-config
"baseHref": ""
// #docregion locale-config
"fr": {
"translation": "src/locale/messages.fr.xlf",
// #enddocregion locale-config
"baseHref": ""
// #docregion locale-config
}
}
},
// #docregion build-production-french
@@ -42,13 +44,8 @@
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.css"],
"scripts": [],
// #docregion missing-translation-error
"i18nMissingTranslation": "error"
@@ -80,6 +77,7 @@
"outputHashing": "all"
},
"development": {
"localize": false,
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
@@ -89,9 +87,7 @@
},
// #docregion build-single-locale, build-production-french
"fr": {
"localize": [
"fr"
]
"localize": ["fr"]
}
},
// #enddocregion build-single-locale, build-production-french
@@ -111,7 +107,7 @@
},
// #docregion build-single-locale, build-production-french
"fr": {
"browserTarget": "angular.io-example:build:fr"
"browserTarget": "angular.io-example:build:development,fr"
}
},
// #enddocregion build-single-locale, build-production-french
@@ -132,13 +128,8 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.css"],
"scripts": []
}
},
@@ -27,7 +27,7 @@
<!-- #docregion formarrayname -->
<div formArrayName="aliases">
<h2>Aliases</h2>
<button type="button" (click)="addAlias()" type="button">+ Add another alias</button>
<button type="button" (click)="addAlias()">+ Add another alias</button>
<div *ngFor="let alias of aliases.controls; let i=index">
<!-- The repeated alias template -->
@@ -0,0 +1,65 @@
// #docplaster
import {Injectable, NgModule} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {
Resolve,
RouterModule,
RouterStateSnapshot,
Routes,
TitleStrategy,
} from '@angular/router'; // CLI imports router
// #docregion page-title
const routes: Routes = [
{
path: 'first-component',
title: 'First component',
component: FirstComponent, // this is the component with the <router-outlet> in the template
children: [
{
path: 'child-a', // child route path
title: ResolvedChildATitle,
component: ChildAComponent, // child route component that the router renders
},
{
path: 'child-b',
title: 'child b',
component: ChildBComponent, // another child route component that the router renders
},
],
},
];
@Injectable({providedIn: 'root'})
export class ResolvedChildATitle implements Resolve<string> {
resolve() {
return Promise.resolve('child a');
}
}
// #enddocregion page-title
// #docregion custom-page-title
export class TemplatePageTitleStrategy extends TitleStrategy {
constructor(private readonly title: Title) {
super();
}
override updateTitle(routerState: RouterStateSnapshot) {
const title = this.buildTitle(routerState);
if (title !== undefined) {
this.title.setTitle(`My Application | ${title}`);
}
}
}
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [
{provide: TitleStrategy, useClass: TemplatePageTitleStrategy},
]
})
export class AppRoutingModule {
}
// #enddocregion custom-page-title
@@ -4,6 +4,6 @@
<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
<a routerLink="/heroes" routerLinkActive="active">Heroes</a>
</nav>
<div [@routeAnimation]="getAnimationData(routerOutlet)">
<router-outlet #routerOutlet="outlet"></router-outlet>
<div [@routeAnimation]="getAnimationData()">
<router-outlet></router-outlet>
</div>
@@ -2,7 +2,7 @@
// #docregion
import { Component } from '@angular/core';
// #docregion animation-imports
import { RouterOutlet } from '@angular/router';
import { ChildrenOutletContexts } from '@angular/router';
import { slideInAnimation } from './animations';
@Component({
@@ -14,8 +14,10 @@ import { slideInAnimation } from './animations';
// #enddocregion animation-imports
// #docregion function-binding
export class AppComponent {
getAnimationData(outlet: RouterOutlet) {
return outlet?.activatedRouteData?.['animation'];
constructor(private contexts: ChildrenOutletContexts) {}
getAnimationData() {
return this.contexts.getContext('primary')?.route?.snapshot?.data?.['animation'];
}
}
// #enddocregion function-binding
@@ -8,8 +8,8 @@
<!-- #enddocregion contact-link -->
</nav>
<!-- #docregion outlets -->
<div [@routeAnimation]="getAnimationData(routerOutlet)">
<router-outlet #routerOutlet="outlet"></router-outlet>
<div [@routeAnimation]="getAnimationData()">
<router-outlet></router-outlet>
</div>
<router-outlet name="popup"></router-outlet>
<!-- #enddocregion outlets -->
@@ -6,7 +6,7 @@
<a routerLink="/admin" routerLinkActive="active">Admin</a>
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
</nav>
<div [@routeAnimation]="getAnimationData(routerOutlet)">
<router-outlet #routerOutlet="outlet"></router-outlet>
<div [@routeAnimation]="getAnimationData()">
<router-outlet></router-outlet>
</div>
<router-outlet name="popup"></router-outlet>
@@ -7,7 +7,7 @@
<a routerLink="/login" routerLinkActive="active">Login</a>
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
</nav>
<div [@routeAnimation]="getAnimationData(routerOutlet)">
<router-outlet #routerOutlet="outlet"></router-outlet>
<div [@routeAnimation]="getAnimationData()">
<router-outlet></router-outlet>
</div>
<router-outlet name="popup"></router-outlet>
@@ -8,8 +8,8 @@
<a routerLink="/login" routerLinkActive="active">Login</a>
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
</nav>
<div [@routeAnimation]="getAnimationData(routerOutlet)">
<router-outlet #routerOutlet="outlet"></router-outlet>
<div [@routeAnimation]="getRouteAnimationData()">
<router-outlet></router-outlet>
</div>
<router-outlet name="popup"></router-outlet>
</div>
@@ -1,7 +1,7 @@
// #docplaster
// #docregion
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ChildrenOutletContexts } from '@angular/router';
import { slideInAnimation } from './animations';
@Component({
@@ -11,7 +11,9 @@ import { slideInAnimation } from './animations';
animations: [ slideInAnimation ]
})
export class AppComponent {
getAnimationData(outlet: RouterOutlet) {
return outlet?.activatedRouteData?.['animation'];
constructor(private contexts: ChildrenOutletContexts) {}
getRouteAnimationData() {
return this.contexts.getContext('primary')?.route?.snapshot?.data?.['animation'];
}
}
@@ -41,12 +41,6 @@ export function myService(options: MyServiceSchema): Rule {
// #enddocregion workspace
// #docregion project-info
// #docregion project-fallback
if (!options.project && typeof workspace.extensions.defaultProject === 'string') {
options.project = workspace.extensions.defaultProject;
}
// #enddocregion project-fallback
const project = (options.project != null) ? workspace.projects.get(options.project) : null;
if (!project) {
throw new SchematicsException(`Invalid project name: ${options.project}`);
@@ -1,18 +1,24 @@
import { Injectable } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';
import { SwUpdate, VersionReadyEvent } from '@angular/service-worker';
// #docregion sw-update
@Injectable()
export class LogUpdateService {
constructor(updates: SwUpdate) {
updates.available.subscribe(event => {
console.log('current version is', event.current);
console.log('available version is', event.available);
});
updates.activated.subscribe(event => {
console.log('old version was', event.previous);
console.log('new version is', event.current);
updates.versionUpdates.subscribe(evt => {
switch (evt.type) {
case 'VERSION_DETECTED':
console.log(`Downloading new app version: ${evt.version.hash}`);
break;
case 'VERSION_READY':
console.log(`Current app version: ${evt.currentVersion.hash}`);
console.log(`New app version ready for use: ${evt.latestVersion.hash}`);
break;
case 'VERSION_INSTALLATION_FAILED':
console.log(`Failed to install app version '${evt.version.hash}': ${evt.error}`);
break;
}
});
}
}
@@ -18,7 +18,6 @@
background-color: #EEE;
margin: .5em;
padding: 0;
height: 1.6em;
border-radius: 4px;
display: flex;
align-items: stretch;
@@ -22,7 +22,6 @@
background-color: #EEE;
margin: .5em;
padding: 0;
height: 1.6em;
border-radius: 4px;
display: flex;
align-items: stretch;
@@ -16,6 +16,28 @@ body, input[type="text"], button {
color: #333;
font-family: Cambria, Georgia, serif;
}
button {
background-color: #eee;
border: none;
border-radius: 4px;
cursor: pointer;
color: black;
font-size: 1.2rem;
padding: 1rem;
margin-right: 1rem;
margin-bottom: 1rem;
margin-top: 1rem;
}
button:hover {
background-color: black;
color: white;
}
button:disabled {
background-color: #eee;
color: #aaa;
cursor: auto;
}
/* everywhere else */
* {
font-family: Arial, Helvetica, sans-serif;
@@ -18,7 +18,6 @@
background-color: #EEE;
margin: .5em;
padding: 0;
height: 1.6em;
border-radius: 4px;
display: flex;
align-items: stretch;
@@ -17,7 +17,6 @@
background-color: #EEE;
margin: .5em;
padding: 0;
height: 1.6em;
border-radius: 4px;
display: flex;
align-items: stretch;
@@ -18,7 +18,6 @@
background-color: #EEE;
margin: .5em;
padding: 0;
height: 1.6em;
border-radius: 4px;
display: flex;
align-items: stretch;
@@ -1,34 +1,39 @@
This is the Angular Phonecat application adjusted to fit our boilerplate project
structure.
This is the Angular Phonecat application adjusted to fit our boilerplate project structure.
The following changes from vanilla Phonecat are applied:
* The TypeScript config file shown in the guide is `tsconfig.ajs.json` instead
of the default, because we don't want to enable `noImplicitAny` for migration.
* Karma config for unit tests is in karma.conf.ajs.js because the boilerplate
Karma config is not compatible with the way AngularJS tests need to be run.
The shell script run-unit-tests.sh can be used to run the unit tests.
* Instead of using Bower, AngularJS and its dependencies are fetched from a CDN
in index.html and karma.conf.ajs.js.
* E2E tests have been moved to the parent directory, where `gulp run-e2e-tests` can
discover and run them along with all the other examples.
* Most of the phone JSON and image data removed in the interest of keeping
repo weight down. Keeping enough to retain testability of the app.
* The TypeScript config file shown in the guide is `tsconfig.ajs.json` instead of the default, because we don't want to enable `noImplicitAny` for migration.
* Karma config for unit tests is in karma.conf.ajs.js because the boilerplate Karma config is not compatible with the way AngularJS tests need to be run.
The shell script run-unit-tests.sh can be used to run the unit tests.
* Instead of using Bower, AngularJS and its dependencies are fetched from a CDN in index.html and karma.conf.ajs.js.
* E2E tests have been moved to the parent directory, where `gulp run-e2e-tests` can discover and run them along with all the other examples.
* Most of the phone JSON and image data removed in the interest of keeping repo weight down. Keeping enough to retain testability of the app.
## Running the app
Start like any example
npm run start
```shell
npm run start
```
You'll find the app under the /app path: http://localhost:3002/app/index.html
You'll find the app under the /app path:
```http
http://localhost:3002/app/index.html
```
## Running unit tests
./run-unit-tests.sh
```shell
./run-unit-tests.sh
```
## Running E2E tests
Like for any example (at the project root):
Like for any example \(at the project root\):
gulp run-e2e-tests --filter=phonecat-1
```shell
gulp run-e2e-tests --filter=phonecat-1
```
@@ -1,32 +1,33 @@
This is the Angular Phonecat application adjusted to fit our boilerplate project
structure.
This is the Angular Phonecat application adjusted to fit our boilerplate project structure.
The following changes from vanilla Phonecat are applied:
* Karma config for unit tests is in karma.conf.ajs.js because the boilerplate
Karma config is not compatible with the way AngularJS tests need to be run.
The shell script run-unit-tests.sh can be used to run the unit tests.
* Also for the Karma shim, there is a `karma-test-shim.1.js` file which isn't
used but is shown in the test appendix.
* Instead of using Bower, AngularJS and its dependencies are fetched from a CDN
in index.html and karma.conf.ajs.js.
* E2E tests have been moved to the parent directory, where `run-e2e-tests` can
discover and run them along with all the other examples.
* Most of the phone JSON and image data removed in the interest of keeping
repo weight down. Keeping enough to retain testability of the app.
* Karma config for unit tests is in karma.conf.ajs.js because the boilerplate Karma config is not compatible with the way AngularJS tests need to be run.
The shell script run-unit-tests.sh can be used to run the unit tests.
* Also for the Karma shim, there is a `karma-test-shim.1.js` file which isn't used but is shown in the test appendix.
* Instead of using Bower, AngularJS and its dependencies are fetched from a CDN in index.html and karma.conf.ajs.js.
* E2E tests have been moved to the parent directory, where `run-e2e-tests` can discover and run them along with all the other examples.
* Most of the phone JSON and image data removed in the interest of keeping repo weight down. Keeping enough to retain testability of the app.
## Running the app
Start like any example
npm run start
```shell
npm run start
```
## Running unit tests
./run-unit-tests.sh
```shell
./run-unit-tests.sh
```
## Running E2E tests
Like for any example (at the project root):
Like for any example \(at the project root\):
gulp run-e2e-tests --filter=phonecat-2
```shell
gulp run-e2e-tests --filter=phonecat-2
```
@@ -3,19 +3,22 @@ structure.
The following changes from vanilla Phonecat are applied:
* E2E tests have been moved to the parent directory, where `run-e2e-tests` can
discover and run them along with all the other examples.
* Most of the phone JSON and image data removed in the interest of keeping
repo weight down. Keeping enough to retain testability of the app.
* E2E tests have been moved to the parent directory, where `run-e2e-tests` can discover and run them along with all the other examples.
* Most of the phone JSON and image data removed in the interest of keeping repo weight down.
Keeping enough to retain testability of the app.
## Running the app
Start like any example
npm run start
```shell
npm run start
```
## Running E2E tests
Like for any example (at the project root):
Like for any example \(at the project root\):
gulp run-e2e-tests --filter=phonecat-3
```shell
gulp run-e2e-tests --filter=phonecat-3
```
+30 -16
View File
@@ -2,37 +2,42 @@
@description
This diagnostic detects a backwards "banana-in-box" syntax for
[two-way bindings](guide/two-way-binding).
This diagnostic detects a backwards "banana-in-box" syntax for [two-way bindings](guide/two-way-binding).
```html
<div ([var])="otherVar"></div>
```
<code-example format="html" language="html">
&lt;div ([var])="otherVar"&gt;&lt;/div&gt;
</code-example>
## What's wrong with that?
As it stands, `([var])` is actually an [event binding](guide/event-binding) with
the name `[var]`. The author likely intended this as a two-way binding to a variable named
`var` but as written this binding has no effect.
As it stands, `([var])` is actually an [event binding](guide/event-binding) with the name `[var]`.
The author likely intended this as a two-way binding to a variable named `var` but, as written, this binding has no effect.
## What should I do instead?
Fix the typo. As the name suggests, the banana `(` should go *inside* the box `[]`. In this case:
Fix the typo.
As the name suggests, the banana `(` should go *inside* the box `[]`.
In this case:
```html
<div [(var)]="otherVar"></div>
```
<code-example format="html" language="html">
&lt;div [(var)]="otherVar"&gt;&lt;/div&gt;
</code-example>
## Configuration requirements
[`strictTemplates`](/guide/template-typecheck#strict-mode) must be enabled for any extended
diagnostic to emit. `invalidBananaInBox` has no additional requirements beyond `strictTemplates`.
[`strictTemplates`](guide/template-typecheck#strict-mode) must be enabled for any extended diagnostic to emit.
`invalidBananaInBox` has no additional requirements beyond `strictTemplates`.
## What if I can't avoid this?
This diagnostic can be disabled by editing the project's `tsconfig.json` file:
```json
<code-example format="json" language="json">
{
"angularCompilerOptions": {
"extendedDiagnostics": {
@@ -42,6 +47,15 @@ This diagnostic can be disabled by editing the project's `tsconfig.json` file:
}
}
}
```
</code-example>
See [extended diagnostic configuration](extended-diagnostics#configuration) for more info.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+66 -42
View File
@@ -2,81 +2,96 @@
@description
This diagnostic detects a useless nullish coalescing operator (`??`) in Angular templates.
Specifically, it looks for operations where the input is not "nullable", meaning its type does not
include `null` or `undefined`. For such values, the right side of the `??` will never be used.
This diagnostic detects a useless nullish coalescing operator \(`??`\) characters in Angular templates.
Specifically, it looks for operations where the input is not "nullable", meaning its type does not include `null` or `undefined`.
For such values, the right side of the `??` will never be used.
```typescript
import {Component} from '@angular/core';
<code-example format="typescript" language="typescript">
@Component({
// Template displays `foo` if present, falls back to 'bar' if it is `null`
// or `undefined`.
template: `<div>{{ foo ?? 'bar' }}</div>`,
// ...
import {Component} from '&commat;angular/core';
&commat;Component({
// Template displays &grave;foo&grave; if present, falls back to 'bar' if it is &grave;null&grave;
// or &grave;undefined&grave;.
template: &grave;
&lt;div&gt;
{{ foo ?? 'bar' }}
&lt;/div&gt;
&grave;,
// &hellip;
})
class MyComponent {
// `foo` is declared as a `string` which *cannot* be `null` or `undefined`.
// &grave;foo&grave; is declared as a &grave;string&grave; which *cannot* be &grave;null&grave; or &grave;undefined&grave;.
foo: string = 'test';
}
```
</code-example>
## What's wrong with that?
Using the nullish coalescing operator with a non-nullable input has no effect and is indicative of a
discrepancy between the allowed type of a value and how it is presented in the template. A developer
might reasonably assume that the right side of the nullish coalescing operator is displayed in some
case, but it will never actually be displayed. This can lead to confusion about the expected output
of the program.
Using the nullish coalescing operator with a non-nullable input has no effect and is indicative of a discrepancy between the allowed type of a value and how it is presented in the template.
A developer might reasonably assume that the right side of the nullish coalescing operator is displayed in some case, but it will never actually be displayed.
This can lead to confusion about the expected output of the program.
## What should I do instead?
Update the template and declared type to be in sync. Double check the type of the input and confirm
whether it is actually expected to be nullable.
Update the template and declared type to be in sync.
Double-check the type of the input and confirm whether it is actually expected to be nullable.
If the input should be nullable, add `null` or `undefined` to its type to indicate this.
```typescript
import {Component} from '@angular/core';
<code-example format="typescript" language="typescript">
@Component({
template: `<div>{{ foo ?? 'bar' }}</div>`,
// ...
import {Component} from '&commat;angular/core';
&commat;Component({
template: &grave;
&lt;div&gt;
{{ foo ?? 'bar' }}
&ltl/div&gt;
&grave;,
// &hellip;
})
class MyComponent {
// `foo` is now nullable. If it is ever set to `null`, 'bar' will be displayed.
foo: string | null = 'test';
// &grave;foo&grave; is now nullable. If it is ever set to &grave;null&grave;, 'bar' will be displayed.
foo: string &verbar; null = 'test';
}
```
If the input should *not* be nullable, delete the `??` operator and its right operand, since the
value is guaranteed by TypeScript to always be non-nullable.
</code-example>
```typescript
import {Component} from '@angular/core';
If the input should *not* be nullable, delete the `??` operator and its right operand, since the value is guaranteed by TypeScript to always be non-nullable.
@Component({
// Template always displays `foo`, which is guaranteed to never be `null` or
// `undefined`.
template: `<div>{{ foo }}</div>`,
// ...
<code-example format="typescript" language="typescript">
import {Component} from '&commat;angular/core';
&commat;Component({
// Template always displays &grave;foo&grave;, which is guaranteed to never be &grave;null&grave; or
// &grave;undefined&grave;.
template: &grave;
&lt;div&gt;
{{ foo }}
&lt;/div&gt;
&grave;,
// &hellip;
})
class MyComponent {
foo: string = 'test';
}
```
</code-example>
## Configuration requirements
[`strictTemplates`](/guide/template-typecheck#strict-mode) must be enabled for any extended
diagnostic to emit. [`strictNullChecks`](/guide/template-typecheck#strict-null-checks) must also be
enabled to emit any `nullishCoalescingNotNullable` diagnostics.
[`strictTemplates`](guide/template-typecheck#strict-mode) must be enabled for any extended diagnostic to emit.
[`strictNullChecks`](guide/template-typecheck#strict-null-checks) must also be enabled to emit any `nullishCoalescingNotNullable` diagnostics.
## What if I can't avoid this?
This diagnostic can be disabled by editing the project's `tsconfig.json` file:
```json
<code-example format="json" language="json">
{
"angularCompilerOptions": {
"extendedDiagnostics": {
@@ -86,6 +101,15 @@ This diagnostic can be disabled by editing the project's `tsconfig.json` file:
}
}
}
```
</code-example>
See [extended diagnostic configuration](extended-diagnostics#configuration) for more info.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+50 -46
View File
@@ -1,32 +1,33 @@
# Extended Diagnostics
There are many coding patterns that are technically valid to the compiler or runtime, but which may
have complex nuances or caveats. These patterns may not have the intended effect expected by a
developer, which often leads to bugs. The Angular compiler includes "extended diagnostics" which
identify many of these patterns to warn developers about the potential issues and enforce common
best practices within a codebase.
There are many coding patterns that are technically valid to the compiler or runtime, but which may have complex nuances or caveats.
These patterns may not have the intended effect expected by a developer, which often leads to bugs.
The Angular compiler includes "extended diagnostics" which identify many of these patterns, in order to warn developers about the potential issues and enforce common best practices within a codebase.
## Diagnostics
Currently, Angular supports the following extended diagnostics:
* [NG8101 - `invalidBananaInBox`](extended-diagnostics/NG8101)
* [NG8102 - `nullishCoalescingNotNullable`](extended-diagnostics/NG8102)
* [NG8101 - `invalidBananaInBox`](extended-diagnostics/NG8101)
* [NG8102 - `nullishCoalescingNotNullable`](extended-diagnostics/NG8102)
## Configuration
Extended diagnostics are warnings by default and do not block compilation. Each diagnostic can be
configured as either:
Extended diagnostics are warnings by default and do not block compilation.
Each diagnostic can be configured as either:
* `warning` (default) - The compiler emits the diagnostic as a warning but does not block
compilation. The compiler will still exit with status code 0, even if warnings are emitted.
* `error` - The compiler emits the diagnostic as an error and fails the compilation. The compiler
will exit with a non-zero status code if one or more errors are emitted.
* `suppress` - The compiler does *not* emit the diagnostic at all.
* `warning` \(default\) - The compiler emits the diagnostic as a warning but does not block compilation.
The compiler will still exit with status code 0, even if warnings are emitted.
* `error` - The compiler emits the diagnostic as an error and fails the compilation.
The compiler will exit with a non-zero status code if one or more errors are emitted.
* `suppress` - The compiler does *not* emit the diagnostic at all.
Check severity can be configured in the project's `tsconfig.json` file:
```jsonc
<code-example format="jsonc" language="jsonc">
{
"angularCompilerOptions": {
"extendedDiagnostics": {
@@ -36,50 +37,53 @@ Check severity can be configured in the project's `tsconfig.json` file:
"invalidBananaInBox": "suppress"
},
// The category to use for any diagnostics not listed in `checks` above.
// The category to use for any diagnostics not listed in &grave;checks&grave; above.
"defaultCategory": "error"
}
}
}
```
The `checks` field maps the name of individual diagnostics to their associated category. See
[Diagnostics](#diagnostics) for a complete list of extended diagnostics and the name to use for
configuring them.
</code-example>
The `defaultCategory` field is used for any diagnostics that are not explicitly listed under
`checks`. If not set, such diagnostics will be treated as `warning`.
The `checks` field maps the name of individual diagnostics to their associated category.
See [Diagnostics](#diagnostics) for a complete list of extended diagnostics and the name to use for configuring them.
Extended diagnostics will emit when [`strictTemplates`](/guide/template-typecheck#strict-mode) is
enabled. This is required to allow the compiler to better understand Angular template types and
provide accurate and meaningful diagnostics.
The `defaultCategory` field is used for any diagnostics that are not explicitly listed under `checks`.
If not set, such diagnostics will be treated as `warning`.
Extended diagnostics will emit when [`strictTemplates`](guide/template-typecheck#strict-mode) is enabled.
This is required to allow the compiler to better understand Angular template types and provide accurate and meaningful diagnostics.
## Semantic Versioning
The Angular team intends to add or enable new extended diagnostics in **minor** versions of Angular
(see [semver](https://docs.npmjs.com/about-semantic-versioning)). This means that upgrading Angular
may show new warnings in your existing codebase. This enables the team to deliver features more
quickly and to make extended diagnostics more accessible to developers.
The Angular team intends to add or enable new extended diagnostics in **minor** versions of Angular (see [semver](https://docs.npmjs.com/about-semantic-versioning)).
This means that upgrading Angular may show new warnings in your existing codebase.
This enables the team to deliver features more quickly and to make extended diagnostics more accessible to developers.
However, setting `"defaultCategory": "error"` will promote such warnings to hard errors. This can
cause a minor version upgrade to introduce compilation errors, which may be seen as a semver
non-compliant breaking change. Any new diagnostics can be suppressed or demoted to warnings via the
above [configuration](#configuration), so the impact of a new diagnostic should be minimal to
projects that treat extended diagnostics as errors by default. Defaulting to error is a very
powerful tool; just be aware of this semver caveat when deciding if `error` is the right default for
your project.
However, setting `"defaultCategory": "error"` will promote such warnings to hard errors.
This can cause a minor version upgrade to introduce compilation errors, which may be seen as a semver non-compliant breaking change.
Any new diagnostics can be suppressed or demoted to warnings via the above [configuration](#configuration), so the impact of a new diagnostic should be minimal to
projects that treat extended diagnostics as errors by default.
Defaulting to error is a very powerful tool; just be aware of this semver caveat when deciding if `error` is the right default for your project.
## New Diagnostics
The Angular team is always open to suggestions about new diagnostics that could be added. Extended
diagnostics should generally:
The Angular team is always open to suggestions about new diagnostics that could be added.
Extended diagnostics should generally:
* Detect a common, non-obvious developer mistake with Angular templates.
* Clearly articulate why this pattern can lead to bugs or unintended behavior.
* Suggest one or more clear solutions.
* Have a low (preferrably zero) false-positive rate.
* Apply to the vast majority of Angular applications (not specific to an unofficial library).
* Improve program correctness or performance (not style, that responsibility falls to a linter).
* Detect a common, non-obvious developer mistake with Angular templates
* Clearly articulate why this pattern can lead to bugs or unintended behavior
* Suggest one or more clear solutions
* Have a low \(preferrably zero\) false-positive rate
* Apply to the vast majority of Angular applications \(not specific to an unofficial library\)
* Improve program correctness or performance \(not style, that responsibility falls to a linter\)
If you have an idea for a compiler check which fits these criteria, consider filing a
[feature request](https://github.com/angular/angular/issues/new?template=2-feature-request.yaml).
If you have an idea for a compiler check which fits these criteria, consider filing a [feature request](https://github.com/angular/angular/issues/new?template=2-feature-request.yaml).
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
+67 -68
View File
@@ -1,65 +1,70 @@
# Accessibility in Angular
The web is used by a wide variety of people, including those who have visual or motor impairments.
A variety of assistive technologies are available that make it much easier for these groups to
interact with web-based software applications.
A variety of assistive technologies are available that make it much easier for these groups to interact with web-based software applications.
In addition, designing an application to be more accessible generally improves the user experience for all users.
For an in-depth introduction to issues and techniques for designing accessible applications, see the [Accessibility](https://developers.google.com/web/fundamentals/accessibility/#what_is_accessibility) section of the Google's [Web Fundamentals](https://developers.google.com/web/fundamentals/).
For an in-depth introduction to issues and techniques for designing accessible applications, see the [Accessibility](https://developers.google.com/web/fundamentals/accessibility/#what_is_accessibility) section of the Google's [Web Fundamentals](https://developers.google.com/web/fundamentals).
This page discusses best practices for designing Angular applications that
work well for all users, including those who rely on assistive technologies.
This page discusses best practices for designing Angular applications that work well for all users, including those who rely on assistive technologies.
<div class="alert is-helpful">
For the sample application that this page describes, see the <live-example></live-example>.
For the sample application that this page describes, see the <live-example></live-example>.
</div>
## Accessibility attributes
Building accessible web experience often involves setting [ARIA attributes](https://developers.google.com/web/fundamentals/accessibility/semantics-aria)
to provide semantic meaning where it might otherwise be missing.
Building accessible web experience often involves setting [ARIA attributes](https://developers.google.com/web/fundamentals/accessibility/semantics-aria) to provide semantic meaning where it might otherwise be missing.
Use [attribute binding](guide/attribute-binding) template syntax to control the values of accessibility-related attributes.
When binding to ARIA attributes in Angular, you must use the `attr.` prefix, as the ARIA
specification depends specifically on HTML attributes rather than properties of DOM elements.
When binding to ARIA attributes in Angular, you must use the `attr.` prefix, as the ARIA specification depends specifically on HTML attributes rather than properties of DOM elements.
```html
<!-- Use attr. when binding to an ARIA attribute -->
<button [attr.aria-label]="myActionLabel">...</button>
```
<code-example format="html" language="html">
Note that this syntax is only necessary for attribute _bindings_.
Static ARIA attributes require no extra syntax.
&lt;!-- Use 'attr.' when binding to an ARIA attribute --&gt;
&lt;button [attr.aria-label]="myActionLabel"&gt;&hellip;&lt;/button&gt;
```html
<!-- Static ARIA attributes require no extra syntax -->
<button aria-label="Save document">...</button>
```
</code-example>
<div class="alert is-helpful">
By convention, HTML attributes use lowercase names (`tabindex`), while properties use camelCase names (`tabIndex`).
**NOTE** <br />
This syntax is only necessary for attribute *bindings*.
Static ARIA attributes require no extra syntax.
See the [Binding syntax](guide/binding-syntax#html-attribute-vs-dom-property) guide for more background on the difference between attributes and properties.
<code-example format="html" language="html">
&lt;!-- Static ARIA attributes require no extra syntax --&gt;
&lt;button aria-label="Save document"&gt;&hellip;&lt;/button&gt;
</code-example>
</div>
<div class="alert is-helpful">
By convention, HTML attributes use lowercase names \(`tabindex`\), while properties use camelCase names \(`tabIndex`\).
See the [Binding syntax](guide/binding-syntax#html-attribute-vs-dom-property) guide for more background on the difference between attributes and properties.
</div>
## Angular UI components
The [Angular Material](https://material.angular.io/) library, which is maintained by the Angular team, is a suite of reusable UI components that aims to be fully accessible.
The [Angular Material](https://material.angular.io) library, which is maintained by the Angular team, is a suite of reusable UI components that aims to be fully accessible.
The [Component Development Kit (CDK)](https://material.angular.io/cdk/categories) includes the `a11y` package that provides tools to support various areas of accessibility.
For example:
* `LiveAnnouncer` is used to announce messages for screen-reader users using an `aria-live` region. See the W3C documentation for more information on [aria-live regions](https://www.w3.org/WAI/PF/aria-1.1/states_and_properties#aria-live).
* `LiveAnnouncer` is used to announce messages for screen-reader users using an `aria-live` region.
See the W3C documentation for more information on [aria-live regions](https://www.w3.org/WAI/PF/aria-1.1/states_and_properties#aria-live).
* The `cdkTrapFocus` directive traps Tab-key focus within an element. Use it to create accessible experience for components like modal dialogs, where focus must be constrained.
* The `cdkTrapFocus` directive traps Tab-key focus within an element.
Use it to create accessible experience for components such as modal dialogs, where focus must be constrained.
For full details of these and other tools, see the [Angular CDK accessibility overview](https://material.angular.io/cdk/a11y/overview).
### Augmenting native elements
Native HTML elements capture a number of standard interaction patterns that are important to accessibility.
@@ -68,17 +73,15 @@ When authoring Angular components, you should re-use these native elements direc
For example, instead of creating a custom element for a new variety of button, create a component that uses an attribute selector with a native `<button>` element.
This most commonly applies to `<button>` and `<a>`, but can be used with many other types of element.
You can see examples of this pattern in Angular Material: [`MatButton`](https://github.com/angular/components/blob/50d3f29b6dc717b512dbd0234ce76f4ab7e9762a/src/material/button/button.ts#L67-L69), [`MatTabNav`](https://github.com/angular/components/blob/50d3f29b6dc717b512dbd0234ce76f4ab7e9762a/src/material/tabs/tab-nav-bar/tab-nav-bar.ts#L139), [`MatTable`](https://github.com/angular/components/blob/50d3f29b6dc717b512dbd0234ce76f4ab7e9762a/src/material/table/table.ts#L22).
You can see examples of this pattern in Angular Material:
[`MatButton`](https://github.com/angular/components/blob/50d3f29b6dc717b512dbd0234ce76f4ab7e9762a/src/material/button/button.ts#L67-L69), [`MatTabNav`](https://github.com/angular/components/blob/50d3f29b6dc717b512dbd0234ce76f4ab7e9762a/src/material/tabs/tab-nav-bar/tab-nav-bar.ts#L139), and [`MatTable`](https://github.com/angular/components/blob/50d3f29b6dc717b512dbd0234ce76f4ab7e9762a/src/material/table/table.ts#L22).
### Using containers for native elements
Sometimes using the appropriate native element requires a container element.
For example, the native `<input>` element cannot have children, so any custom text entry components need
to wrap an `<input>` with additional elements.
While you might just include the `<input>` in your custom component's template,
this makes it impossible for users of the component to set arbitrary properties and attributes to the input element.
Instead, create a container component that uses content projection to include the native control in the
component's API.
For example, the native `<input>` element cannot have children, so any custom text entry components need to wrap an `<input>` with additional elements.
While you might just include the `<input>` in your custom component's template, this makes it impossible for users of the component to set arbitrary properties and attributes to the input element.
Instead, create a container component that uses content projection to include the native control in the component's API.
You can see [`MatFormField`](https://material.angular.io/components/form-field/overview) as an example of this pattern.
@@ -86,65 +89,61 @@ You can see [`MatFormField`](https://material.angular.io/components/form-field/o
The following example shows how to make a progress bar accessible by using host binding to control accessibility-related attributes.
* The component defines an accessibility-enabled element with both the standard HTML attribute `role`, and ARIA attributes. The ARIA attribute `aria-valuenow` is bound to the user's input.
* The component defines an accessibility-enabled element with both the standard HTML attribute `role`, and ARIA attributes.
The ARIA attribute `aria-valuenow` is bound to the user's input.
<code-example path="accessibility/src/app/progress-bar.component.ts" header="src/app/progress-bar.component.ts" region="progressbar-component"></code-example>
<code-example header="src/app/progress-bar.component.ts" path="accessibility/src/app/progress-bar.component.ts" region="progressbar-component"></code-example>
* In the template, the `aria-label` attribute ensures that the control is accessible to screen readers.
* In the template, the `aria-label` attribute ensures that the control is accessible to screen readers.
<code-example path="accessibility/src/app/app.component.html" header="src/app/app.component.html" region="template"></code-example>
<code-example header="src/app/app.component.html" path="accessibility/src/app/app.component.html" region="template"></code-example>
## Routing and focus management
Tracking and controlling [focus](https://developers.google.com/web/fundamentals/accessibility/focus/) in a UI is an important consideration in designing for accessibility.
Tracking and controlling [focus](https://developers.google.com/web/fundamentals/accessibility/focus) in a UI is an important consideration in designing for accessibility.
When using Angular routing, you should decide where page focus goes upon navigation.
To avoid relying solely on visual cues, you need to make sure your routing code updates focus after page navigation.
Use the `NavigationEnd` event from the `Router` service to know when to update
focus.
Use the `NavigationEnd` event from the `Router` service to know when to update focus.
The following example shows how to find and focus the main content header in the DOM after navigation.
```ts
<code-example format="typescript" language="typescript">
router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
const mainHeader = document.querySelector('#main-content-header')
router.events.pipe(filter(e =&gt; e instanceof NavigationEnd)).subscribe(() =&gt; {
const mainHeader = document.querySelector('&num;main-content-header')
if (mainHeader) {
mainHeader.focus();
}
});
```
In a real application, the element that receives focus will depend on your specific
application structure and layout.
</code-example>
In a real application, the element that receives focus will depend on your specific application structure and layout.
The focused element should put users in a position to immediately move into the main content that has just been routed into view.
You should avoid situations where focus returns to the `body` element after a route change.
## Additional resources
* [Accessibility - Google Web Fundamentals](https://developers.google.com/web/fundamentals/accessibility)
* [ARIA specification and authoring practices](https://www.w3.org/TR/wai-aria/)
* [Material Design - Accessibility](https://material.io/design/usability/accessibility.html)
* [Smashing Magazine](https://www.smashingmagazine.com/search/?q=accessibility)
* [Inclusive Components](https://inclusive-components.design/)
* [Accessibility Resources and Code Examples](https://dequeuniversity.com/resources/)
* [W3C - Web Accessibility Initiative](https://www.w3.org/WAI/people-use-web/)
* [Rob Dodson A11ycasts](https://www.youtube.com/watch?v=HtTyRajRuyY)
* [Angular ESLint](https://github.com/angular-eslint/angular-eslint#functionality) provides linting rules that can help you make sure your code meets accessibility standards.
* [Accessibility - Google Web Fundamentals](https://developers.google.com/web/fundamentals/accessibility)
* [ARIA specification and authoring practices](https://www.w3.org/TR/wai-aria)
* [Material Design - Accessibility](https://material.io/design/usability/accessibility.html)
* [Smashing Magazine](https://www.smashingmagazine.com/search/?q=accessibility)
* [Inclusive Components](https://inclusive-components.design)
* [Accessibility Resources and Code Examples](https://dequeuniversity.com/resources)
* [W3C - Web Accessibility Initiative](https://www.w3.org/WAI/people-use-web)
* [Rob Dodson A11ycasts](https://www.youtube.com/watch?v=HtTyRajRuyY)
* [Angular ESLint](https://github.com/angular-eslint/angular-eslint#functionality) provides linting rules that can help you make sure your code meets accessibility standards.
Books
* "A Web for Everyone: Designing Accessible User Experiences", Sarah Horton and Whitney Quesenbery
* "A Web for Everyone: Designing Accessible User Experiences", Sarah Horton and Whitney Quesenbery
* "Inclusive Design Patterns", Heydon Pickering
* "Inclusive Design Patterns", Heydon Pickering
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28

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