Commit graph

136 commits

Author SHA1 Message Date
Alan Agius
7907e982ee test: remove duplicate tests
These tests are duplicate and have been removed.
2026-03-11 13:35:26 -07:00
Sonu Kapoor
4a9b715b3a test(forms): cover transformedValue without FormField context
Adds a test verifying that `transformedValue` exposes parse errors via
the returned signal's `parseErrors()` property when no FormField
context is present.

This ensures that:
- parse errors are still observable without DI-based field propagation
- the model is not updated when `parse` omits `value`
- valid input clears parse errors and updates the model

This test protects the documented contract that DI-based error
propagation is expected for FormValueControl usage, while standalone
usage relies on explicit consumption of `parseErrors()`.

(cherry picked from commit 71b8159b37)
2026-03-09 23:41:52 +00:00
Leon Senft
670d1660c4 feat(forms): add 'blur' option to debounce rule
Expands the `debounce` rule configuration to accept `'blur'`. When this option
is provided, the rule will delay model synchronization until the field loses
focus (is touched). This introduces a debouncer that defers resolution
until the framework automatically aborts pending debounces upon touch events.

(cherry picked from commit c767d678cf)
2026-03-05 17:55:18 +00:00
Miles Malerba
bdfb60f3e3 fix(forms): use consistent error format returned from parse
Aligns the errors returned from the `parse` function in
`transformedValue` to use the same convention as the rest of signal
forms (a property called `error` that can contain a single error or list
of errors)

(cherry picked from commit 23fd8fa586)
2026-02-23 17:11:55 +00:00
cexbrayat
631f60d1f9 fix(forms): preserve parse errors when parse returns value
Fixes #67170 by keeping the errors even a value is returned from the parse function.

(cherry picked from commit fe25c57a5c)
2026-02-20 18:28:57 +00:00
Leon Senft
567f292e8e fix(forms): support custom controls as host directives
Add the missing code to update control properties when control is a host
directive.

Fix #66592.
2026-02-18 14:06:54 -08:00
Leon Senft
dcb9af6dfa test(forms): [formField] synchronizes with a host directive
Test that `[formField]` synchronizes its value with a custom form
control implemented as a host directive on a component.
2026-02-18 14:06:54 -08:00
Miles Malerba
30f0914754 feat(forms): support binding null to number input (#66917)
Supports binding `null` to a `<input type=number>`.

- Binding in `null` clears the input
- Binding in `NaN` also clears the input
- When the user clears the input, the model is set to `null`
- The model is _never_ set to `NaN` based on user interaction. It is
  either set to `null` if the user cleared the input, or is unchanged
  and a parse error added if the user entered an invalid number like
  "42e"

PR Close #66917
2026-02-13 12:11:06 -08:00
Miles Malerba
22afbb2f36 feat(forms): add parsing support to native inputs (#66917)
Integrates native inputs with the new parseErrors API so that they can
report parse errors when the user types an un-parsable value (e.g. "42e"
in a number field).

When a user types an un-parsable value, the model does not update. It
retains its previous value and a parse error is added for the control
that received the un-parsable value.

PR Close #66917
2026-02-13 12:11:06 -08:00
Miles Malerba
27397b3f4f fix(forms): clear parse errors when model updates (#66917)
Changes `parsedErrors` to a `linkedSignal` based on the model value.
This ensures that the parse errors are reset if the model changes from
outside the control.

PR Close #66917
2026-02-13 12:11:06 -08:00
cexbrayat
63d8005703 fix(forms): preserve custom-control focus context in signal forms
Fixes #67051

Store custom control focus callbacks in a wrapper so method invocation keeps the original object context. Without this, custom focus methods that access instance members throw at runtime when focusBoundControl() is called.
2026-02-13 09:37:19 -08:00
Miles Malerba
d75046bc09
fix(forms): warn when showing hidden field state
In signal forms, it is up to the user to guard hidden fields from being
rendered in the template. To help catch instances where it is
accidentally not guarded, this commit introduces a warning in dev mode.
2026-02-11 14:46:43 -08:00
Leon Senft
3606902b33
refactor(forms): relax [formField] input type from FieldTree to Field
`FieldTree` was an unnecessarily specific type for the `[formField]`
input. It forced the directive to care about what _kind_ of `FieldTree`
was bound–specifically whether it was Reactive Forms compatible or not.
This made it difficult to author forms system-agnostic components with
passthrough `[formField]` inputs.
2026-02-11 11:45:20 -08:00
Miles Malerba
ba009b6031
feat(forms): add form directive
Adds a `formRoot` directive to manage submitting the form in signal
forms.
2026-02-10 14:34:48 -08:00
Miles Malerba
f56bb07d83 feat(forms): add field param to submit action and onInvalid
The `action` and `onInvalid` handlers now recevie two pieces of
information:
1. The form that is being submitted
2. The specific field that the submit was triggered on

Remove the `submit()` method on field state - supporting this is complex
from a typing perspective, since the `FieldState` only knows its
`TValue` type, not the `TModel` type of its owning `FieldTree`. Rather
than try to pack additional generics on to `FieldState`, we'll just
leave the `submit` function as a standalone importable function.
2026-02-09 14:49:43 -08:00
Leon Senft
b772f518f1 refactor(forms): add fieldTree property to FieldState
The `fieldTree` property of `FieldState` returns its associated
`FieldTree`.

Note that the round trip from `FieldTree` to `FieldState` and back will
lose type information. This is because `FieldState` intentionally does
not know whether it came from a pure Signal Forms field tree, or a
Reactive Forms compatible field tree:

```ts
// Pure Signal Forms:
const x: FieldTree<string>;

x();           // FieldState<string>;
x().fieldTree; // FieldTree<unknown>

// Reactive Forms compatibility:
const y: FieldTree<FormControl<string>>;

y();            // FieldState<string>;
y().fieldTree;  // FieldTree<unknown>;
```
2026-02-09 12:28:35 -08:00
Miles Malerba
adfb83146b
fix(forms): simplify design of parse errors
Reoves the `parseErrors` property on `FormUiControl` and instead
introduces a new utility `transformedValue` that automatically handles
synchronizing the raw value and model value using the given `parse` and
`format` functions. It also automates the reporting of `parseErrors` to
the `FormField`, simplifying the API surface
2026-02-09 12:27:41 -08:00
Angular Robot
11767cabe4 build: update Jasmine to 6.0.0
Jasmine enables `forbidDuplicateNames: true` by default. So we also need to desambiguate duplicate spec names.
2026-02-09 12:15:57 -08:00
SkyZeroZx
24c0c5a180 feat(forms): support signal-based schemas in validateStandardSchema
Allow `validateStandardSchema()` to consume a computed schema so
validation rules stay in sync when the schema changes over time.

This supports schemas stored in computed signals (e.g. zod schemas that
depend on input signals) and ensures the effective schema updates after
initialization instead of being captured once.

Fixes #66867
2026-02-06 07:40:46 -08:00
Miles Malerba
95ecce8334 feat(forms): allow setting submit options at form-level
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().
2026-02-03 12:43:31 -08:00
Miles Malerba
dd208ca259 feat(forms): update submit function to accept options object
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.
2026-02-03 12:43:31 -08:00
kirjs
c750b3cf11 refactor(forms): Setup closure compatible property override
We have to do this because Abstract control doesn't allow us to have value as a getter type-wise
2026-02-02 14:51:40 -08:00
kirjs
80f08838b0 refactor(forms): Address more feedback
Clean up tests, drop old todos
2026-02-02 14:51:40 -08:00
kirjs
fdae63c11f refactor(forms): Address more feedback
Make the way reset works for it to be more consistent
2026-02-02 14:51:40 -08:00
kirjs
e4eeb3adc0 refactor(forms): Address more feedback
Untrack callbacks, so they are not called when signals change
2026-02-02 14:51:40 -08:00
kirjs
b3b5611096 refactor(forms): Address more feedback
Document that injectors are optional
2026-02-02 14:51:40 -08:00
kirjs
0df5442f4e refactor(forms): Address more feedback
- Add more comments and docs
- In signalErrorsToValidationErrors return null for empty object
- Drop messages in prod mode
2026-02-02 14:51:40 -08:00
kirjs
8e80575ff4 refactor(forms): address feedback
Consolidate everything related to converting errors in one place
2026-02-02 14:51:40 -08:00
kirjs
05d5087252 refactor(forms): use markAsPristine and markAsUntouched on field node
This make things cleaner
2026-02-02 14:51:40 -08:00
kirjs
bbbdf0a6ed refactor(forms): add unsupported method errors and docs
- Add disable, enable methods that throw with helpful messages
- Add validator methods (set/add/remove/clear) that throw
- Add setErrors, markAsPending methods that throw
- Add setters for dirty/pristine/touched/untouched that throw
- Add JSDoc with @usageNotes examples
- Add comprehensive unit tests for SignalFormControl
- Add FormGroup/FormArray integration tests
- Add web tests for CVA directive lifecycle
- Update migration docs with SignalFormControl usage
2026-02-02 14:51:40 -08:00
Leon Senft
26d12158e1
refactor(forms): convert FieldState.controlValue to a WritableSignal
Remove `setControlValue()` from `FieldState` and convert `controlValue` to a
`WritableSignal` whose setter implements the debounced syncing behavior
of `setControlValue()`.
2026-01-30 09:14:14 -08:00
Leon Senft
e682e53113 fix(forms): only touch visible, interactive fields on submit
Don't touch hidden, disabled, or readonly fields on submit, since they
don't contribute to form validity. This also prevents errors from
appearing immediately if they're later made interactive.

Fix #66344
2026-01-28 18:56:02 +00:00
Leon Senft
01bfb83fc9 test(forms): submit behavior while validation is pending
Ensure `submit()` behaves as expected while a form is pending.

- Submission is not blocked by pending validation.
- Submission errors prevent pending validation errors from appearing
  after they resolve on the same field.
- Submission errors don't prevent pending validation errors from
  appearing after they resolve on subfields.
2026-01-28 00:15:29 +00:00
Miles Malerba
fb05fc86d0
fix(forms): sort error summary by DOM order
This will allow users to rely on the `errorSummary` order to implement
features like "focus next error"
2026-01-26 22:29:07 +00:00
Miles Malerba
ebae211add feat(forms): introduce parse errors in signal forms
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`.
2026-01-22 22:19:10 +00:00
SkyZeroZx
95c386469c feat(forms): Add passing focus options to form field
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.
2026-01-16 13:24:27 -08:00
Miles Malerba
e7b2dde6d1 fix(forms): fix control value syncing on touch
Previously we were unconditionally setting the control value back into
the value, regardless of if it had actually been changed. This PR
changes the logic to flush the pending sync on touch if there is one, or
just skip it if there isn't.
2026-01-16 09:25:27 -08:00
Miles Malerba
5974cd0afc
feat(forms): Ability to manually register a form field binding in signal forms
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`.
2026-01-15 11:03:28 -08:00
Matthieu Riegler
65fa5b5439 fix(forms): Ensure the control instruction comes after the other bindings
Prior to this change, binding to radio value was sensitive to the order in which `value` & `formField` where binding in the template.
The compiler change makes that order non-important.

fixes #66402
2026-01-12 13:49:19 -08:00
cexbrayat
7fd076bdd3 test(forms): improve test coverage for multiple pattern validators
Add comprehensive test cases to validate behavior when multiple
pattern validators are applied to the same field.

These tests clarify that multiple patterns operate with AND logic,
where each pattern is validated independently and produces its own
error when it doesn't match.
2026-01-12 13:48:16 -08:00
Miles Malerba
10e9022a07 feat(forms): allow focusing bound control from field state
Allows focusing the assocated bound control from the `FieldState`.
2026-01-12 09:59:42 -08:00
Miles Malerba
5671f2cc07
fix(forms): Rename signal form [field] to [formField]
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]`
2026-01-09 14:33:09 -08:00
Leon Senft
46dbd18566 refactor(forms): remove customError()
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`.
2026-01-07 15:07:30 -05:00
SkyZeroZx
e7d99f02cb fix(forms): clean up abort listener after timeout
Removes the abort event listener once the debounce timeout completes.

This avoids lingering listeners, prevents potential memory leaks, and ensures
the abort logic runs at most once.
2026-01-07 14:07:25 -05:00
Miles Malerba
2d85ae5811 feat(forms): add [formField] directive
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
2026-01-06 17:21:06 -05:00
Leon Senft
82a2de201f refactor(forms): bind native properties on interop controls
The framework will now bind all field state properties to their
corresponding native properties (if any) on interop form controls (those
using `ControlValueAccessor`), excluding those handled explicitly by
`ControlValueAccessor` such as `disabled`.
2026-01-06 13:12:17 -05:00
Leon Senft
15bddbdcda refactor(forms): bind field properties to all directives on interop controls
The framework will now bind the field state properties to all matching
directive inputs on form controls using Reactive Forms'
`ControlValueAccessor`.
2026-01-06 13:12:17 -05:00
Leon Senft
0c8f15d546 refactor(forms): bind field properties to all directives on custom controls
The framework will now bind the field state properties to all matching
directive inputs on custom form controls.
2026-01-06 13:12:17 -05:00
Leon Senft
c149f47ef6 refactor(forms): bind field properties to all directives on native controls
Since the `Field` directive manages binding `FieldState` properties to
the underlying form control automatically, the type checker prohibits
explicit bindings to the same properties to avoid conflicts. This proved
problematic in cases where developers wanted to bind these properties to
the inputs of other directives on form controls. Now the framework will
bind the field state properties to all matching directive inputs on
native controls.

Fix #65617
2026-01-06 13:12:17 -05:00
kirjs
282220d032 fix(forms): Support readonly arrays in signal forms
This would allow using `readonly Array<...>` in types
2026-01-02 08:26:06 +01:00