This adds a setTimeout, which guarantees that we call getAnimations one frame after a reflow is finished. This means getAnimations will return data, avoiding needing the expensive fallback of getComputedStyles. It also updates the cleanup to prevent a potential memory leak if the component is destroyed before the timeout runs.
(cherry picked from commit 318ade062e)
This updates the determineLongestAnimation code to also calculate the playback rate in with the duration, which should also account for timing when testing with playback rates changed in devtools.
(cherry picked from commit 17d8a88ddc)
Fixes that we weren't sanitizing the `form` and `formaction` attributes when they're used together with translations.
(cherry picked from commit de0eb4c656)
This reverts commit ea2016a6dc.
This reverts the support for nested animations due to the global scope of how nested animations were gathered.
This caused issues where on route navigations, all child nodes with animations would be queued and run before the navigation would occur.
We'll be revisiting the nested animations with a more tightened scope of when those leave animations will occur.
fixes: #67552
(cherry picked from commit 999c14eaab)
The `toString()` implementations in the primitives package intended to include
the debug name, yet the debug name was evaluated during construction before it
could ever have been assigned. This commit fixes that.
The Angular wrappers override the `toString()` representation to evaluate signals
ad-hoc instead of showing their internal state, and this commit aligns their
behavior to include the debug name in `toString` as well.
(cherry picked from commit b401c18674)
Fixes that we weren't sanitizing attribute bindings with interpolations if they're marked for translation, for example: `<a href="{{evilLink}}" i18n-href></a>`.
Also adds a bit more test coverage for our sanitization.
(cherry picked from commit 8630319f74)
Use feature detection for `Uint8Array.prototype.toBase64` and
`Uint8Array.fromBase64`, falling back to the existing implementation
when native support is not available
PR Close#67002
This ensures that when calculating longest animations, we completely ignore infinite animations. This will prevent mistakes with using the API and hopefully catch any unexpected bugs.
fixes: #67350
(cherry picked from commit 9758ea9ee9)
This addresses a reported issue where elements were being fully removed from the DOM during drag and drop operations.
fixes: #67257
(cherry picked from commit 0b59cba85d)
Translators are not allowed to write HTML which creates URI attributes. I opted to ban any values going into an attribute at all, to prevent even links to malicious content, rather than just sanitizing URIs.
I also converted this blocklist into an allowlist. Now, we only allowing setting known attributes (while sanitizing URI attributes). This significantly reduces risk of missing a vulnerable attribute and does not require an exhaustive list of all potential attributes.
BREAKING CHANGE: Angular now only applies known attributes from HTML in translated ICU content. Unknown attributes are dropped and not rendered.
(cherry picked from commit 306f367899)
Addresses an issue where the LCP image observer incorrectly identified LCP elements when the same image URL was used multiple times on a page
Fixes#53278
(cherry picked from commit 38749698d0)
When using ViewContainerRef to rapidly toggle animated elements in
zoneless mode (e.g. CDK Overlay menus), multiple copies of the element
could appear in the DOM. This happened because leave animations were
queued but not yet executed, and the existing `cancelLeavingNodes`
mechanism could not find the leaving element to cancel it — it ran
during template execution before the new element was in the DOM, and
used the declaration container's anchor which doesn't work for
overlay/portal patterns where elements are moved to separate
containers.
Animation runner functions (runEnterAnimation, runLeaveAnimations,
runLeaveAnimationFunction) execute asynchronously from the animation
queue via afterNextRender. By that time the lView injector may have
been destroyed, causing lView[INJECTOR].get(NgZone) to throw NG0205.
Move the NgZone and MAX_ANIMATION_TIMEOUT lookups into the setup
instructions (ɵɵanimateEnter, ɵɵanimateLeave, ɵɵanimateLeaveListener)
which run synchronously during template processing when the injector
is guaranteed to be valid, and pass them through the closures.
The dynamic component has `[value]` in its selector and this has always been reflected as a DOM attribute on the dynamically created host element, which is now also synced into the component instance.
fixes#60157
Encodes arraybuffer and blob response bodies as base64 when storing in the transfer cache, ensuring correct retrieval and usage on the client side.
Fixes#66827
Now if there's a leave animation nested within a template, those will animate before the parent element is removed. This makes animating leaving elements a bit easier than before and adds a lot more flexibility to how animations can be structured.
fixes: #66476
Unlike a normal `signal()`, a `linkedSignal()` can be in an error state when
its computation fails. Currently, there's a bug where `linkedSignal.update`
does not account for this error state, and will pass the internal `ERRORED`
`Symbol` as the current value to the updater function.
This commit fixes the issue by having `update()` check and throw the error
instead of calling the updater function.
Adds `ChangeDetectionStrategy.Eager` as an explicit alias for `ChangeDetectionStrategy.Default`. This improves readability when contrasting with `OnPush`, clarifying that the component will be checked eagerly when traversal reaches it.
Compiler findings:
- The compiler resolves `ChangeDetectionStrategy` enum members by value in `resolveEnumValue` (see `packages/compiler-cli/src/ngtsc/annotations/common/src/evaluation.ts`).
- Since `Eager` has usage value `1` (same as `Default`), it is correctly interpreted during static analysis.
- At runtime, `defineComponent` (in `packages/core/src/render3/definition.ts`) checks `changeDetection === ChangeDetectionStrategy.OnPush` (0). Any other value, including `1` (Eager/Default), results in eager checking behavior (`onPush: false`).
Refactors the `ɵɵcontrolCreate` and `ɵɵcontrol` instructions to delegate control logic to the forms package via new `ɵngControlCreate` and `ɵngControlUpdate` lifecycle hooks. Previously, the logic for binding form state to native elements and custom controls was hardcoded within `@angular/core`.
**Compiler Changes:**
- Introduces a new compilation phase `specializeControlProperties` (in `control_directives.ts`).
- This phase detects properties named `formField` and specializes them into `ControlCreate` and `Control` IR opcodes.
- These opcodes emit `ɵɵcontrolCreate` and `ɵɵcontrol` instructions, respectively.
**Runtime Changes:**
- `ɵɵcontrolCreate` acts as the creation phase. It locates the control directive and invokes its `ɵngControlCreate` method.
- `ɵɵcontrol` acts as the update phase, and invokes the control directive's `ɵngControlUpdate` method (if present).
- Introduces a `passThroughInput` configuration in `ControlFeature`. This specifies the input name (e.g., `formField`) that triggers the control. If the runtime detects that this input is bound to multiple targets (e.g., the `FormField` directive *and* the host component), the control is flagged as "pass-through". In this state, `ɵngControlCreate` returns a no-op update function, deferring responsibility to the other consumer (e.g., the component managing the field itself).
**Forms Changes:**
- `FormField` directive implements `ɵngControlCreate` and `ɵngControlUpdate`.
- Inside this hook, `FormField` determines the type of control it is attached to (Native, CVA, or Custom Signal Control) and delegates to the appropriate handler (`nativeControlCreate`, `cvaControlCreate`, or `customControlCreate`).
- Consolidates all form binding logic within `@angular/forms/signals`, enabling support for new `FormValueControl` and `FormCheckboxControl` interfaces.
- Reorganizes the codebase by moving `FormField` from `api/` to `directive/` and splitting the binding logic into semantic pieces:
- `control_native.ts`, `control_cva.ts`, and `control_custom.ts` contain the specific handlers for each control type.
- `native.ts` and `select.ts` provide helpers for native element discovery and select-specific synchronization.
- `bindings.ts` manages the tracking and application of property/attribute bindings.
When dynamic components are rapidly added and removed with animate.leave and animate.enter, a leave animation might fire before the enter animation could, causing an element to be retained. This fix prevents that from occuring by clearing the enter animations in this case.
fixes: #66794
Add the host/container comment node to the `DeferBlockData`. This node can be used as a `@defer` block locator in the DOM tree in the absence of root nodes.
PR Close#66546
Currently migrating from `[ngClass]` to `[class]` isn't entirely supported, because `[ngClass]` supports `Set` values while `[class]` ignores them.
These changes add a bit of logic to bring them closer together and make the migration easier.
* Define `ResourceSnapshot<T>` as a type union of possible states for a
`Resource<T>`.
* Add `Resource.snapshot()` to convert a `Resource` to a signal of its
snapshot.
* Add `resourceFromSnapshots` to convert a reactive snapshot back into a
`Resource`.
By converting resources from/to `Signal<ResourceSnapshot>`s, full
composition of resources is now possible on top of signal composition APIs
like `computed` and `linkedSignal`.
For example, a common feature request is to have a `Resource` which retains
its value when its reactive source (params) changes. This can now be built
as a utility, leveraging `linkedSignal`'s previous value capability:
```ts
function withPreviousValue<T>(input: Resource<T>): Resource<T> {
const derived = linkedSignal({
source: input.snapshot,
computation: (snap, previous) => {
if (snap.status === 'loading' && previous?.value) {
// When the input resource enters loading state, we keep the value
// from its previous state, if any.
return {status: 'loading', value: previous.value.value};
}
// Otherwise we simply forward the state of the input resource.
return snap;
},
});
return resourceFromSnapshots(derived);
}
// In application code:
userId = input.required<number>();
user = withPreviousValue(httpResource(() => `/user/{this.userId()}`));
// if `userId()` switches, `user.value()` will keep the old value until
// the new one is ready!
```
Error message links now point to the archived documentation site (v*.angular.dev)
so that referenced content matches the framework version in use.
See angular#44650
PR Close#66374
This completes the rename started in #66136. `[field]` is too generic of
a selector for the forms system to own, and likely to cause naming
collisions with existing components. Therefore it is being renamed to
`[formField]`