Wrap operationsCounter method calls (recordCreate, recordDestroy, reset)
with ngDevMode guards to ensure they are tree-shaken in production builds.
This aligns with the existing pattern where operationsCounter is only
initialized in development mode, and eliminates unnecessary method call
overhead in production.
The optional chaining (?.) is retained as TypeScript doesn't narrow types
based on ngDevMode checks, but the entire expression will be removed during
production builds.
(cherry picked from commit 80dbd74ae8)
This PR makes a number of changes to the metadata API to address design
flaws in the previous API. Some of the changes include:
- Replaces the previous `MetadataKey` and `AggregateMetadataKey` with a
single unified `MetadataKey` that is used for all metadata.
- The new `MetadataKey` is only defined for fields that explicitly set
it in their schema logic
- All metadata now has reducer / aggregate behavior
- The new `MetadataKey` has an option to create a managed key which
wraps the result of its computed aggregate into some other structure
such as a `Resource` or `linkedSignal`
- There are now two APIs to create metadata keys
- `createMetadataKey` for pure computed metadata
- `createManagedMetadataKey` for metadata that manages its computation
internally
(cherry picked from commit ebc5c2b083)
FormUiControl states that hidden, pending and dirty will be bind in custom controls, but this is currently not the case.
Fixes#65575
(cherry picked from commit 9fe9566581)
This change replaces all remaining occurrences of `typeof ngDevMode !== undefined`
with the correct `typeof ngDevMode !== 'undefined'` form. This aligns the codebase
with JavaScript typeof semantics and maintains consistency with other Angular code.
(cherry picked from commit 96b79fc393)
Replace the 'any' type with ClassDebugInfo for the debugInfo parameter in
stringifyTypeFromDebugInfo function. This removes the TODO comment that was
tracking the need for proper typing without creating circular dependencies.
The change improves type safety while avoiding circular imports since
stringify_utils.ts doesn't export anything that definition.ts imports.
(cherry picked from commit 5fd75410a9)
- Use getComponentDef in debugStringifyTypeForError to clean up TODO
- Remove outdated comment from stringify_utils
(cherry picked from commit 0bb8924ab6)
Previously, navigating a `FieldTree` in signal forms involved reactive reads
of the value of the parent field(s), both directly and via `.childrenMap()`.
This meant that on _any_ change to the value of a field, reactive
notifications would trigger updates of computeds, reruns of effects, etc.
So for example, this effect would run on every change to the form:
```ts
const f = form(signal({data: 'abc', unrelated: 0}));
effect(() => {
// accessing f.data incurs a dependency on f().value() which changes
// on every change in the whole form
console.log(f.data().value());
});
```
This is deeply counterintuitive and troublesome when attempting to write
effect logic, and also results in `computed`s unnecessarily updating.
This change introduces the concept of a "reader" computed, which memoizes
the access of a field at a given key via the reactive graph. With this, the
same `f.data` access above now depends on the `data` reader in `f` only,
which is effectively a constant computed. As a result, the effect only
reruns on changes to `data`'s value, as intended.
PR Close#65802
Previously, several values were being passed into the creation of
`FieldNodeStructure`s that were only used in the creation of child nodes.
Separately, we also passed a `createChildNode` function which these values
were passed back into.
Instead, this moves the small bit of logic from structure.ts behind the
`createChildNode` callback, which reduces the passing of values back-and-
forth and gives `createChildNode` a much more suitable signature.
PR Close#65802
Extends the `FormUiControl` interface to allow `InputSignalWithTransform` in addition to `InputSignal` for its properties.
Fixes#65756
(cherry picked from commit 7d1e502345)
Move the instructions used to dynamically bind a `Field` directive to a
form control onto the `Field` itself. This way the instructions are only
retained if the app uses the `Field` directive.
PR Close#65599
When registering providers, the DI system assumes that `viewProviders` are registered before plain `providers`. This was reinforced by components always being first in the array of directive matches, only one component being allowed per node and the fact that only components can have `viewProviders`.
This breaks down if there are host directives with `providers` on the component, because they'll execute earlier, throwing off the order of operations.
These changes fix the issue by separating out the resolvers for `viewProviders` and plain `providers` and explicitly running the component's `viewProviders` resolver before any others. This also has the benefit of not attempting to resolve `viewProviders` for directives which are guaranteed not to have them.
Fixes#65724.
(cherry picked from commit 886cf6c452)
Previously, the XSRF interceptor only added the XSRF token to requests with relative URLs.
This commit updates the interceptor to also add the token to requests with absolute URLs, provided they match the current origin.
(cherry picked from commit 0659d11c85)
Adds some type checking code which verifies that the bound `value` on a `Field` radio button is a string.
Fixes#65726.
(cherry picked from commit 6773d3b97d)
This commit adds a `.catch()` handler to `transition.finished` from `document.startViewTransition` to prevent unhandled promise rejections. The finished promise can reject with `TimeoutError` or `InvalidStateError` when transitions fail during or after the animation phase.
Based on the Blink source code, the `finished` promise can reject with:
* `TimeoutError`: "Transition was aborted because of timeout in DOM update"
* `InvalidStateError`: "Transition was aborted because of invalid state"
This may happen when the DOM update phase exceeds the browser's internal timeout threshold.
(cherry picked from commit b74a0693f2)
The end of the Router navigation is a block of synchronous logic that
can be compressed into a single operator rather than splitting it across
several, making it harder to step through. The only benefit from the
split is automatic unsubscribe/cancellation, which we can replicate
with an additional 'shouldContinue' check before proceeding.
(cherry picked from commit b7d21e209a)
Currently when the signal debug name transform sees something like `const foo = signal(0);`, it transforms the signal into `signal(0, {...(ngDevMode ? { debugName: 'foo' } : {})})`. After minification this becomes `signal(0, {})` which will allocate memory for the empty object literal.
These changes rework the logic to produce `signal(0, ...(ngDevMode ? [{ debugName: 'foo' }] : []))` which will be fully tree shaken away to `signal(0)`.
(cherry picked from commit e30e61b789)
In the case that a component injector is destroyed before the animation
queue runs, the animation queue would fail to run because it was using a
destroyed injector. This commit changes the animation queue to run in the
context of the EnvironmentInjector, which is not destroyed until the app
is destroyed.
fixes: #65628
(cherry picked from commit d8ab83ca82)
This is necessary to exclude a race condition where the MutationObserver initialized by the instruction fired before the inputs are binded.
fixes#65678
(cherry picked from commit f35b2ef47c)
Improves the symbol linking logic to handle Angular component selectors (e.g., ngCombobox). It attempts to convert Angular selector patterns to their corresponding class names, improving navigation to Angular API documentation.
(cherry picked from commit 2d854e01bc)
This commit implements a security fix to prevent XSS vulnerabilities where SVG animation elements (`<animate>`, `<set>`, etc.) could be used to modify the `href` or `xlink:href` attributes of other elements to `javascript:` URLs.
(cherry picked from commit 1c6b0704fb)
With the change we specifically analyse `boostrapApplication` with a config that uses `mergeApplicationConfig`.
fixes#65408
(cherry picked from commit c1dfd9cde6)
Add test coverage for bundling dynamic component creation API like
`createComponent()` and `inputBinding()`. This will be used to test that
Signal Forms related features for #64632 can be tree-shaken when unused.
(cherry picked from commit add8c41e5b)
The XSRF interceptor previously failed to detect protocol-relative URLs (starting with `//`) as absolute URLs. This allowed requests to such URLs to include the XSRF token, potentially leaking it to external domains.
This change updates the interceptor to correctly identify protocol-relative URLs as absolute and exclude them from receiving the XSRF token.
(cherry picked from commit 40790ef980)
Adds a mark for signal forms so we can track adoption. Also moves the call for `@let` into `declareLet` since we don't need it to fire as often as in `storeLet`.
(cherry picked from commit c994267f17)
This ensures that the right document is used and that `CSP_NONCE` can be used in `provideAppInitializer` and `provideEnvironmentInitializer`.
Closes#65624
(cherry picked from commit 3b1fa8235b)
Escape @-prefixed template control flow constructs during doc extraction so JSDoc parsing keeps description text intact. Add regression coverage for @for snippets.
(cherry picked from commit 5bfa027d41)
Adds a DI configuration option for signal forms that allows the
developer to specify CSS classes that should be automatically added
by the `Field` directive based on the field's status.
(cherry picked from commit c70e246c23)
The type checker will no longer prohibit binding the Signal Forms `[field]`
directive to an input with a dynamic `[attr.type]` or `[type]` binding.
(cherry picked from commit 3a1eb07c46)