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)
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)
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)
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
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
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
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.
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.
`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.
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.
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>;
```
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
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
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.
Remove `setControlValue()` from `FieldState` and convert `controlValue` to a
`WritableSignal` whose setter implements the debounced syncing behavior
of `setControlValue()`.
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
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.
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.
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.
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`.
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
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.
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]`
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`.
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.
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
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`.
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