Updates FormOptions to accept a submission configuration object.
This allows defining default submit options (action, validation behavior, etc.)
when creating the form, which can be overridden when calling submit().
Changes the `submit` function signature to accept a `FormSubmitOptions` object instead of a direct action callback.
This allows for more flexibility, including:
- `action`: The standard submit action to perform with the data.
- `onInvalid`: A callback to execute when the submit action is not triggered due to failing validation
- `ignoreValidators`: Controls whether pending validators or invalid validators should be ignored
Also updates the return value of `submit` to a `Promise<boolean` to indicate submission success.
Enables specifying a custom browser URL for router links via a new input,
allowing navigation to use an explicit browser URL in navigation options.
Closes#66805
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`).
This commit introduces a JSON schema for angularCompilerOptions in the
Angular Language Service extension. It provides validation and autocompletion
for Angular-specific options in tsconfig.json files.
Remove `setControlValue()` from `FieldState` and convert `controlValue` to a
`WritableSignal` whose setter implements the debounced syncing behavior
of `setControlValue()`.
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.
Consolidating the standard schema support into `standard_schema.ts` will
cut down on unnecessary g3 patch changes whenever we change
`validation_errors.ts`.
This updates `RouterLinkActive`, `Router.isActive`, and the standalone
`isActive` function to accept `Partial<IsActiveMatchOptions>` which uses
the current default values as the base (paths and queryParams are
subset, fragment and matrix params are ignored).
fixes#53326
Adds dedicated `LocationStrategy` subclasses: `NoTrailingSlashPathLocationStrategy` and `TrailingSlashPathLocationStrategy`.
The `TrailingSlashPathLocationStrategy` ensures that URLs prepared for the browser always end with a slash, while `NoTrailingSlashPathLocationStrategy` ensures they never do. This configuration only affects the URL written to the browser history; the `Location` service continues to normalize paths by stripping trailing slashes when reading from the browser.
Example:
```typescript
providers: [
{provide: LocationStrategy, useClass: TrailingSlashPathLocationStrategy}
]
```
This approach to the trailing slash problem isolates the changes to the
existing LocationStrategy abstraction without changes to Router, as was
attempted in two other options (#66452 and #66423).
From an architectural perspective, this is the cleanest approach for several reasons:
1. Separation of Concerns and "Router Purity": The Router's primary job is to map a URL structure to an application state (ActivatedRoutes). It shouldn't necessarily be burdened with the formatting nuances of the underlying platform unless those nuances affect the state itself. By pushing trailing slash handling to the LocationStrategy, you treat the trailing slash as a "platform serialization format" rather than a "router state" concern. This avoids the "weirdness" in #66423 where the UrlTree (serialization format) disagrees with the ActivatedRouteSnapshot (logical state).
2. Tree Shakability: If an application doesn't care about trailing slashes (which is the default "never" behavior), they don't pay the cost for that logic. It essentially becomes a swappable "driver" for the URL interaction.
3. Simplicity for the Router: #66452 (consuming the slash as a segment) bleeds into the matching logic, potentially causing issues with child routes or wildcards effectively "eating" a segment that should be invisible. This option leaves the matching logic purely focused on meaningful path segments by continuing to strip the trailing slash on read.
4. Consistency with Existing Patterns: Angular already uses LocationStrategy to handle Hash vs Path routing. Adding "Trailing Slash" nuances there is a natural extension of that pattern—it's just another variation of "how do we represent this logic in the browser's address bar?"
fixes#16051
Parse errors allow a custom control to communicate that it is currently
unable to produce a valid value.
Parse errors are reported by implementing the optional `parseErrors`
property on the `FormUiControl`. The property should be a signal of the
current parse errors.
Also renames several `*Field` types to `*FieldTree`. This aligns with the new naming of the concept after `Field` was renamed
to `FieldTree`.
Extends the `focus` method of form fields and custom controls to accept and propagate `FocusOptions`.
This enables developers to control focus behavior more precisely, for example, preventing scrolling when focusing an element.
This PR adds the ability to manually register a binding with the
`FormField` directive. This is useful for a lower-level implementation
that takes the field tree as an `input()` rather than relying on the
automatic binding from `FormUiControl`.
* 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!
```
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]`
This commit introduces a highly requested `trailingSlash` configuration option to the Angular Router, allowing developers to control how trailing slashes are handled in their applications. The options are:
- 'always': Enforces a trailing slash on all URLs.
- 'never': Removes trailing slashes from all URLs (default).
- 'preserve': Respects the presence or absence of a trailing slash as defined in the UrlTree.
This publishes the work that was done to integrate with the Navigation
API as an experimental router feature. Browser support is limited and in
active development. There are also known bugs in the browser implementations
and only Chromium browsers supported deferred URL updates with the
`precommitHandler`. Relates to #53321, which I would likely not mark as
completed until this is at least in dev preview, which likely won't
happen until it is widely available and potentially delayed until
`precommitHandler` is widely available as well.
The final form of this api might not even be a "router feature" in the end, but instead be
something similar to what other frameworks have to provide different
platform integrations (e.g. `provideNavigationRouter`). That would
support omitting the history-based integration from the bundle when only
the navigation integration is used. Alternatively, the current
`provideRouter` could require one of `withHistory` or `withPlatformNavigation`.
Remove the `customError` function and `CustomValidationError` type.
These were made obsolete by support for returning plain object literals
as custom errors.
This also catches few `field` properties that were missed in the
renaming to `fieldTree`.
This change deprecates `Router.isActive` in favor of a function that
creates a computed which tracks whether a given url/UrlTree is active,
following changes in the router state.
`Router.isActive` contributes ~1333b to the bundle size, but is only
used by developers who use the API directly or who use
`RouterLinkActive`. It should not contribute to bundle sizes of
applications that do not use this functionality.
This will replace the `[field]` directive, since `[field]` is a very
generic name for signal forms to commandeer
refactor(forms): hook up `formField` directive in compiler
Hooks up the `formField` direcive to get the same treatment as the
`field` directive in the compiler.
apply updated formatting
Adds new tree-shakeable runtime error codes to improve error reporting for
NgModule resolution issues (duplicate or missing IDs) and invalid ViewContainerRef
operations involving destroyed views.
This commit introduces a new feature to automatically destroy `EnvironmentInjector`s associated with routes that are no longer active or stored. This helps in managing memory by releasing resources held by unused injectors.
Adds new runtime sanitization error codes. Adds `ngDevMode` guards around
error message strings to ensure detailed diagnostics are included only
in development mode. This allows production builds to tree-shake verbose error descriptions, reducing bundle size.
This commit adds a utility method to debug why the application has not stabilized after
a set period of time (9 seconds, or `hydrationTimeout-1`).
fixes#52912
The `RESPONSE_INIT` token previously used `ResponseInit`. However, `@types/node` (and `undici`) definitions for `ResponseInit` mark properties as `readonly`, which differs from the standard DOM `ResponseInit`.
This commit introduces a `ResponseInit` type that explicitly removes `readonly` modifiers to ensure compatibility and allow for mutable options. This type is now used by the `RESPONSE_INIT` token and is exported from `@angular/core`.
Updates signal forms to pass the full `Field` directive to the class
configuration functions, rather than just the state. This allows
developers to take the element as well as the state into consideration
when deciding classes to apply.
Closes#65762
BREAKING CHANGE: The shape of `SignalFormsConfig.classes` has changed
Previously each function in the `classes` map took a `FieldState`. Now
it takes a `Field` directive.
For example if you previously had:
```
provideSignalFormsConfig({
classes: {
'my-valid': (state) => state.valid()
}
})
```
You would need to update to:
```
provideSignalFormsConfig({
classes: {
'my-valid': ({state}) => state().valid()
}
})
```
Currently circular references in user code manifest themselves with an error like `Cannot read properties of undefined (reading 'ɵcmp')`. This is a bit cryptic so these changes add an assertion mentioning circular references.
Relates to #65917.
Prevents the deprecation warning that was incorrectly triggered when
defining an InjectionToken with only a `factory`, which correctly
defaults to the `root` scope.