Angular has long had the ability to use different interpolation delimiters
(by default `{{` and `}}`). This concept was copied over from AngularJS,
where AngularJS syntax is included in HTML sent over the network to the
browser. Occasionally developers would use SSR frameworks which _also_ have
interpolation syntaxes of their own, so there was a need to change the
delimiters used by AngularJS to avoid conflicts.
Since Angular templates are always processed by our compiler and the
interpolation characters are never processed by other systems first, this
option is vestigial in Angular and only increases the complexity of our
parser.
DEPRECATED: `@Component.interpolation` is deprecated. Use Angular's
delimiters instead.
PR Close#55778
This reuses information already recorded during hydration to
remove jsaction attributes to also stash event handlers. This avoids
a tree walk and looku.
PR Close#55747
The first test asserts that bubbling does not work right now.
The second asserts that stopPropagation works, which should pass when test #1 passes too.
The third test asserts properties about the events passed to the event handler.
THe fourth test asserts that mouse events do not translate to jsaction nor help emit the jsaction binary. This required a change in code to make this pass.
PR Close#55747
Rename `BaseDispatcher` to `Dispatcher` and `Dispatcher` to
`LegacyDispatcher`. The `GlobalHandler` type and `stopPropagation`
function needs to be left for now in dispatcher.ts as it was not
exported previously from legacy_dispatcher.ts.
PR Close#55721
Since we aren't using clang anymore, we can remove the comments and the workarounds that were in place to prevent it from doing the wrong thing.
PR Close#55750
This commit adds a feature that is useful for determining if an
application is zoneless-ready. The way this works is generally only
useful right now when zoneless is enabled. Some version of this may be useful in
the future as a general configuration option to change detection to make
`checkNoChanges` pass always exhaustive as an opt-in to address #45612.
Because this is an experimental, debug-only feature, it is okay to merge
during the RC period.
PR Close#55663
Rather than attempting to use the native timing functions, this commit
simplifies the logic significantly by using the global timer functions
as they are, either patched or unpatched. When Zone is defined, we run
the timers in the root zone. This has more predictable behavior and
timing than (a) using both patched and unpatched versions of timers in
different places (b) trying to get an unpatched timer and failing due to
environment specifics and patches that aren't ZoneJS.
PR Close#55366
This commit removes the `@developerPreview` annotation from the `@defer` APIs, effectively promoting them (and the entire feature!) to stable.
PR Close#55625
This also adds a test to make sure that the event contract is still listening to other events, especially in the case where we may want partial hydration in the future.
PR Close#55549
This reverts commit 7e89753eef.
Running render hooks inside the zone is specifically problematic for
`afterRender` hooks. If the callback has async task, it would cause an
infinite change detection. In addition, updating state in render hooks
is generally discourages and certainly should update state in a way that
notifies Angular of the change (either via signal or with `markForCheck`) rather
than relying on ZoneJS to pick it up (which would only work if the
change is done inside an async task).
PR Close#55624
This commit fixes an error in the looping logic of `ApplicationRef.tick`
when the tick skips straight to render hooks. In this case, if a render
hook makes a state update that requires a view refresh, we would never
actually refresh the view and just loop until we hit the loop limit.
PR Close#55623
Fixes that even though we weren't rendering the deferred block the server, we were still triggering the timeout which can delay the response.
Fixes#55475.
PR Close#55605
This commit ensures we flush animations by calling renderFactory
begin/end in cases where the ApplicationRef._tick happens in a mode that
skips straight to the render hooks.
PR Close#55564
This commit adds detailed description for the errors NG0955 and NG0956.
Those errors correspond to the check introduced in the built-in for loop.
PR Close#55591
This commit prevents doubling change detections when the zoneless
scheduler is notified first, followed by the zone becomeing unstable
(effectively "scheduling" zone-based change detection). When run
coalescing is enabled, this would otherwise result in the zoneless
scheduler running change detection first and then change detection
running again because of the run coalescing since both scheduler use the
same timing function (and then it would be FIFO).
PR Close#55403
In Angular today, a bound listener automatically marks the view for
check. When using ZoneJS, these listeners are most often executed in the
Angular Zone as well, so synchronization (`ApplicationRef.tick`) will
eventually happen. _However_, developers can opt out of zone-patching
for events in several ways, and often do this for very frequent
listeners like `mousemove`, `resize`, and `scroll`. We do not want to
break existing expectations that these are now "safe" events to have
listeners for by automatically scheduling change detection regardless of
whether the listener executed inside or outside the Angular zone.
In contrast, in order for developers to more easily transition to zoneless,
we need to be able to ensure that components which are using `OnPush`
are, for the most part, compatible with zoneless as well. Because listeners
automatically mark the component for check, developers using `OnPush`
did not/do not need to also call `ChangeDetectorRef.markForCheck` or a
similar API. Unfortunately, this means that we need to consider the
listener callbacks as a notification to schedule a `tick` when Zoneless
is enabled. In the future, we would like to have an opt-out for this
(i.e. signal components) since it's not really how we _want_ things to work.
Also includes the fix for #54919 that got reverted only because it was
easier to revert the set of conflicting commits
PR Close#55525
This commit modifies the setup of the injector profiler to occur solely when the application is running in a browser context. This adjustment is made because the injector profile serves no purpose when the application is running on the server.
PR Close#55530
The timing of render hook execution is almost entirely identical to
`ngZone.onMicrotaskEmpty`. Developers working towards zoneless
compatibility will need to migrate `onMicrotaskEmpty` calls to use
`afterNextRender`/`afterRender` instead. This, however, would lead to
confusing issues if there are promises in the callbacks because
`onMicrotaskEmpty` emits inside the Angular zone while render hooks
execute outside today. This is problematic because it's not documented
and does not produce any notification or error message when async work
is done inside the hooks that requires change detection. Instead, change detection
simply does not run, and this behavior has proven to be surprising to
developers who are used to ZoneJS change detection behavior.
fixes#55299
PR Close#55399
Currently fallback content for `ng-content` gets declared and rendered out in one go. This breaks down if multiple instances of the same component are used where one doesn't render the fallback content while the other one does, because the `TNode` for the content has to be created during the first creation pass.
These changes resolve the issue by always _declaring_ the template, but only rendering it if the slot is empty.
Fixes#55466.
PR Close#55478
The ExperimentalPendingTasks service was accidently exposing one of its
internal fields as a public one. This commit fixes this by marking the
field in question as private.
PR Close#55516
In Angular today, a bound listener automatically marks the view for
check. When using ZoneJS, these listeners are most often executed in the
Angular Zone as well, so synchronization (`ApplicationRef.tick`) will
eventually happen. _However_, developers can opt out of zone-patching
for events in several ways, and often do this for very frequent
listeners like `mousemove`, `resize`, and `scroll`. We do not want to
break existing expectations that these are now "safe" events to have
listeners for by automatically scheduling change detection regardless of
whether the listener executed inside or outside the Angular zone.
In contrast, in order for developers to more easily transition to zoneless,
we need to be able to ensure that components which are using `OnPush`
are, for the most part, compatible with zoneless as well. Because listeners
automatically mark the component for check, developers using `OnPush`
did not/do not need to also call `ChangeDetectorRef.markForCheck` or a
similar API. Unfortunately, this means that we need to consider the
listener callbacks as a notification to schedule a `tick` when Zoneless
is enabled. In the future, we would like to have an opt-out for this
(i.e. signal components) since it's not really how we _want_ things to work.
PR Close#55492
The new ExperimentalPendingTasks API lets developers to add and remove
tasks that control applications stability: a pending task prevents
application from being stable.
This API is important for all the use-cases that depend on the concept
of stability and SSR serialization is a notable example.
Closes#53381
PR Close#55487
This change ensures that `ApplicationRef.tick` flushes animations by
calling `rendererFactory2.end`. This might not have happened before if
there were no views that needed to be refreshed.
This is also likely to fix a potential regression caused by #53718 even
in zone apps where animations don't get flushed when no views attached
to ApplicationRef are dirty.
PR Close#55132
This commit updates the logic to take into account a situation when Event Replay feature is enabled (using `withEventReplay()` method), but there were no events configured in an application. In this case, there is no need to setup an event dispatcher and trigger event replay.
PR Close#55502
The `DeferBlockFixture.render` function should not await the
`whenStable` promise of the fixture. This does not allow developers to
test any intermediate states that might occur between rendering the
initial content and the full app stability.
fixes#55235
PR Close#55271
Adds a check that disables the timer scheduling for `placeholder` and `loading` blocks on the server since the underlying timer will delay the server response.
Fixes#55475.
PR Close#55480
`RouterOutlet` uses a unique injector logic that returns a value that correspond to the `ActivatedRoute` token dynamically. This logic breaks when a component/directive/pipe that injects the `ActivatedRoute` is located within a `@defer` block, because defer creates an `EnvironmentInjector` instance, which doesn't have that dynamic logic.
We've added some special handling of the `OutletInjector` in one of the previous commits, but it was incomplete and it was not covering cases when different routes use the same component. This commit updates defer logic to re-establish this dynamic behavior for `ActivatedRoute` by creating an instance of the `OutletInjector` when a parent injector was also an instance of `OutletInjector`.
This fix is a short-term solution and longer term we should find a way to achieve the dynamic behavior that Router relies on, but without adding a special case logic into defer.
Resolves#54864.
PR Close#55374
This commit introduces a check plus an associated warning for situations where
the combination of the collection change and the tracking expression resulted
in the entire view structure managed by @for to be re-created.
The check uses the following conditions before raising a warning:
- the entire collection was re-created and there were no other operations (ex.: move);
- views in a collection are considered "expensive" to re-create;
- a developer is using tracking by identity.
The last condition tries to capture cases where changes to immutable data
collections can cause significent performance and / or corectness problems.
Note that this warning might be "overreacting" and report cases where
the collection re-creation is the intended behavior. Still, the assumption is that
most of the time it is undesired.
PR Close#55314
This commit fixes an error in a previous commit which attempted to read
`data` from the first item in the apply args array, even if it was not
defined.
PR Close#55465
This commit a new check that warn users about duplicated keys detected given
a tracking expression and a collection iterated over with @for. Duplicated keys
should be avoided as those are more expensive to manage and can result in
incorrect UI display.
PR Close#55243
This commit adds helpful stack information for the case when change
detection continues to be triggered in the event loop and would cause
the browser to freeze.
PR Close#55231
There is an existing pattern that zone-based applications use to avoid
`ExpressionChangedAfterItHasBeenCheckedError` which is also used in
`NgModel`: update the state in a microtask instead of doing it
synchronously. This defers the state update to another round of change
detection, and with ZoneJS, also still executes in the same event loop.
These types of changes across multiple rounds of change detection were
still executed before the browser paint.
This update allows the `NgModel` workaround to continue working in
Zoneless. This may not be permanent and is certainly still not
advisable. Render hooks (`afterNextRender`/`afterRender`) will execute between these
rounds of change detection when they are intended to be run after all
DOM updates completed.
PR Close#55231
This commit ensures we correctly handle the exit from the zone.run in
the zoneless scheduler. Run coalescing would delay the `onMicrotaskEmpty` event
until after we have exited the change detection triggered by the
zoneless scheduler and mean that the subscription cannot determine if
`ApplicationRef.tick` should be skipped.
PR Close#55352
For ideal DOM usage, you would not unwrap an ElementRef outside of the browser. However, it's reasonable to want to find the tag name of the host node on the server, and so this introduces a HOST_TAG_NAME token that can be injected to read this value.
PR Close#54751
When Angular receives a clear indication that change detection should
run again, this should not be ignored, regardless of what Zone it
happened in. This change updates the default change detection scheduling
approach of Zone-based applications to ensure a change detection will
run when these events happen outside the Angular zone (which includes,
for example, updating a signal that's read in a template, setting an
input of a `ComponentRef`, attaching a view marked for check, calling
`ChangeDetectorRef.markForCheck`, etc.).
This does not apply to applications using `NoopNgZone` or those which
have a custom `NgZone` implementation without ZoneJS.
The impact of this change will most often be seen in existing unit tests. Tests
execute outside the Angular Zone and this can mean that state in the
test is not fully recognized by Angular. Now that Angular will ensure
change detection _does_ run, even when the state update originates from
outside the zone, tests may observe additional rounds of change
detection compared to the previous behavior. Often, this should be seen
as more correct and the test should be updated, but in cases where it is
too much effort to debug, the test can revert to the old behavior by adding
`provideZoneChangeDetection({schedulingMode: NgZoneSchedulingMode.NgZoneOnly})`
to the `TestBed` providers.
fixes#55238fixes#53844fixes#53841fixes#52610fixes#53566fixes#52940fixes#51970fixes#51768fixes#50702fixes#50259fixes#50266fixes#50160fixes#49940fixes#49398fixes#48890fixes#48608fixes#45105fixes#42241fixes#41553fixes#37223fixes#37062fixes#35579fixes#31695fixes#24728fixes#23697fixes#19814fixes#13957fixes#11565fixes#15770fixes#15946fixes#18254fixes#19731fixes#20112fixes#22472fixes#23697fixes#24727fixes#47236
BREAKING CHANGE:
Angular will ensure change detection runs, even when the state update originates from
outside the zone, tests may observe additional rounds of change
detection compared to the previous behavior.
This change will be more likely to impact existing unit tests.
This should usually be seen as more correct and the test should be updated,
but in cases where it is too much effort to debug, the test can revert to the old behavior by adding
`provideZoneChangeDetection({schedulingMode: NgZoneSchedulingMode.NgZoneOnly})`
to the `TestBed` providers.
Similarly, applications which may want to update state outside the zone
and _not_ trigger change detection can add
`provideZoneChangeDetection({schedulingMode: NgZoneSchedulingMode.NgZoneOnly})`
to the providers in `bootstrapApplication` or add
`schedulingMode: NgZoneSchedulingMode.NgZoneOnly` to the
`BootstrapOptions` of `bootstrapModule`.
PR Close#55102
Rather than attempting to use the native timing functions, this commit
simplifies the logic significantly by using the global timer functions
as they are, either patched or unpatched. When Zone is defined, we run
the timers in the root zone. This has more predictable behavior and
timing than (a) using both patched and unpatched versions of timers in
different places (b) trying to get an unpatched timer and failing due to
environment specifics and patches that aren't ZoneJS.
We will try to update the coalescing behavior of ZoneJS in a future PR
to also just use the patched version of the timers instead of the
"fakeTopEvent" workaround with the native timers.
PR Close#55367