This commit updates the reactive template and host binding consumers to
only mark their declaration components for refresh, but not parents/ancestors.
This also updates the `AfterViewChecked` hook to run when a component is
refreshed during change detection but its host is not. It is reasonable
to expect that the `ngAfterViewChecked` lifecycle hook will run when a
signal updates and the component is refreshed. The hooks are typically
run when the host is refreshed so without this change, the update to
not mark ancestors dirty would have caused `ngAfterViewChecked` to not
run.
resolves#14628resolves#22646resolves#34347 - this is not the direct request of the issue but
generally forcing change detection to run is necessary only because a
value was updated that needs to be synced to the DOM. Values that use
signals will mark the component for check automatically so accessing the
`ChangeDetectorRef` of a child is not necessary. The other part of this
request was to avoid the need to "mark all views for checking since
it wouldn't affect anything but itself". This is directly addressed by
this commit - updating a signal that's read in the view's template
will not cause ancestors/"all views" to be refreshed.
PR Close#52302
Currently, the migration always use `$index` in the migrated trackBy function, whereas this variable might be aliased.
The compiler then errors with:
```
error TS2339: Property '$index' does not exist on type 'UsersComponent'.
110 @for (user of users; track byId($index, user); let i = $index) {
```
This commit updates the migration to use the aliased index if there is one.
PR Close#52423
Issue #50320 shows that in some cases, updating a signal that's a dependency
of a template during change detection of that template can have several
adverse effects. This can happen, for example, if the signal is set during
the lifecycle hook of a directive within the same template that reads the
signal.
This can cause a few things to happen:
* Straightforwardly, it can cause `ExpressionChanged` errors.
* Surprisingly, it can cause an assertion within the `ReactiveLViewConsumer`
to fail.
* Very surprisingly, it can cause change detection for an `OnPush` component
to stop working.
The root cause of these later behaviors is subtle, and is ultimately a
desync between the reactive graph and the view tree's notion of "dirty" for
a given view. This will be fixed with further work planned for change
detection to handle such updates directly. Until then, this commit improves
the DX through two changes:
1. The mechanism of "committing" `ReactiveLViewConsumer`s to a view is
changed to use the `consumerOnSignalRead` hook from the reactive graph.
This prevents the situation which required the assertion in the first
place.
2. A `console.warn` warning is added when a view is marked dirty via a
signal while it's still executing.
The warning informs users that they're pushing data against the direction of
change detection, risking `ExpressionChanged` or other issues. It's a
warning and not an error because the check is overly broad and captures
situations where the application would not actually break as a result, such
as if a `computed` marked the template dirty but still returned the same
value.
PR Close#52234
Previously, because the platform injector does not have a provider container, this API would fail. Now, we account for this case specifically by returning the found providers immediately, without trying to calculate their importpaths.
Also previously, in the case where a boostrapped standalone component did not import any feature modules, the environment injector connected to that bootstrapped component would be the root injector configured by `bootstrapApplication`. This injector is configured through a `providers` array instead of an `imports` array, and also does not have a provider container. Similarly to the platform case, we account this for this by returning the found providers immediately if there is no provider container for our standalone component.
PR Close#52365
Previously this case was missed by the default framework injector profiler. Now in ngDevMode this event emits correctly when a service is configured with `providedIn`. This includes the case where injection tokens are configured with a `providedIn`.
This commit also includes unit tests for this new case in the injector profiler.
PR Close#52365
Angular recently gained a local compilation mode (see commit
345dd6d81a). This is intended to be used
with the TypeScript compiler option isolatedModules, which bans imports
of const enums.
This changes all const enums tagged with @publicApi to regular enums.
Fixes#46240
PR Close#51670
This updates the code to handle switches more elegantly in line with how the other blocks are handled. This allows nesting to be handled just like other blocks.
PR Close#52358
This commit runs change detection in a loop while there are still dirty
views to be refreshed in the tree. At the moment, this only applies to
transplanted views but will also apply to views with changed signals.
fixes angular#49801
PR Close#51854
When migrating an ng-template later on in a file, the migrationResult was not being reset to zero and causing offsets to be double applied due to ng-template nodes being included in the migration loop.
PR Close#52355
This commit updates the logic to ignore `after` and `minimum` conditions when `DeferBlockFixture.render` method is used in tests.
Resolves#52313.
PR Close#52314
This commit updates the code to report errors via `ErrorHandler` instance.
For dependency loading problems, errors are reported only when `@error` block is not provided.
PR Close#52320
This updates offset to handle pre and post offset properly for nested situations, rather than relying on solely nestCount. This should properly apply offset calculations at the right time to handle any nested situation.
PR Close#52332
This commit adds the logic to cleanup all triggers once defer block is triggered.
When a trigger is created, its cleanup function is stored alongside other defer block info. Prefetch and regular triggers are store in different slots, since we need to invoke them at different time.
PR Close#52291
A few performance improvements and code cleanups in the after render hooks:
1. We were wrapping each `destroy` callback in another callback, because it was typed as `|undefined`. This is unnecessary, because the callback is guaranteed to exist. These changes pass the `destroy` function around directly and avoid the additional callback.
2. In server platforms we were recreating a noop `AfterRenderRef` on each invocation. We can save some memory by returning the same one.
3. Reworks the `AfterRenderCallback` so that it injects `NgZone` and `ErrorHandler` itself, instead of expecting them to be passed in. This reduces the amount of repetition in the code.
PR Close#52292
The current way of computing a route's params and data recomputes
inherited data from the inheritance root every time. When the
inheritance strategy is "emptyOnly", this isn't necessarily the root of
the tree, but some point along the way (it stops once it reaches an
ancestor route with a component).
Instead, this commit updates parameter inheritance to only inherit data
directly from the parent route (again, instead of recomputing all
inherited data back to the inheritance root). The only requirement for
making this work is that the parent route data has already calculated
and updated its own inherited data. This was really already a
requirement -- parents need to be processed before children.
In addition, the update to the inheritance algorithm in this commit
requires more of an understanding that a resolver running higher up in
the tree has to propagate inherited data downwards. The previous
algorithm hid this knowledge because resolvers would recompute inherited
data from the root when run. However, routes that did not have resolvers
rerun or never had resolvers at all would not get the updated resolved data.
fixes#51934
PR Close#52167
Removed the signals property definition from the Component interface since it already exists in the Directive interface and Component inherits from Directive
PR Close#52039
This commit refactors a couple places to improve performance:
* avoid checking parent tree if a current node has "skip hydration" flag
* avoid calling `isInSkipHydrationBlock` if there is no hydration info present
PR Close#52221
A lot of our tests are wrapped in `{}` which serves no purpose, aside from increasing the nesting level and, in some cases, causing confusion. The braces appear to be a leftover from a time when all tests were wrapped in a `function main() {}`. The function declaration was removed in #21053, but the braces remained, presumably because it was easier to search&replace for `function main()`, but not to remove the braces at the same time.
PR Close#52239
This commit updates the message that we output in the console (once hydration is completed) to drop the reference to the developer preview.
PR Close#52197
Assuming that the trackBy function is a pure derivation from the collection
object and its index, we can skip trackBy calculation if items in the live
and new colelction have the same identity and index. Additionally this change
minimizes access to the LContainer array.
PR Close#52227
This adds the support of `if ` conditions with `as` clause when migrating to the control flow syntax.
It now adds the required semicolon before the `as` when migrating the template.
Before: `@if (user$ | async as user) {`
After: `@if (user$ | async; as user) {`
PR Close#52181
Public afterRender phases have specific API guarantees which can be invalidated if the internal framework is implemented using them. Instead, the framework should use dedicated internal functions.
PR Close#52145
This commit drops the `ɵ` symbol from hydration annotation key: `__ɵnghData__` -> `__nghData__`. This helps ensure that there are no UTF8 symbols that might be damaged in case a web server is misconfigured.
Noticed while working on https://github.com/angular/angular/pull/52206.
PR Close#52207
We have the `DEFER_BLOCK_DEPENDENCY_INTERCEPTOR` DI token that we use in tests to intercept the dependency loading function from deferred blocks, however we were referencing it in a way that caused it to be retained in production bundles as well.
These changes guard the call site with `ngDevMode` since the token is only used for testing.
PR Close#52199