@angular/forms 21.1.0-next.4 → 21.1.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license Angular v21.1.0-next.4
3
- * (c) 2010-2025 Google LLC. https://angular.dev/
2
+ * @license Angular v21.1.0-rc.0
3
+ * (c) 2010-2026 Google LLC. https://angular.dev/
4
4
  * License: MIT
5
5
  */
6
6
 
@@ -88,6 +88,52 @@ declare class Field<T> {
88
88
  static ɵdir: i0.ɵɵDirectiveDeclaration<Field<any>, "[field]", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
89
89
  }
90
90
 
91
+ /**
92
+ * Lightweight DI token provided by the {@link FormField} directive.
93
+ *
94
+ * @category control
95
+ * @experimental 21.0.0
96
+ */
97
+ declare const FORM_FIELD: InjectionToken<FormField<unknown>>;
98
+ /**
99
+ * Binds a form `FieldTree` to a UI control that edits it. A UI control can be one of several things:
100
+ * 1. A native HTML input or textarea
101
+ * 2. A signal forms custom control that implements `FormValueControl` or `FormCheckboxControl`
102
+ * 3. A component that provides a `ControlValueAccessor`. This should only be used for backwards
103
+ * compatibility with reactive forms. Prefer options (1) and (2).
104
+ *
105
+ * This directive has several responsibilities:
106
+ * 1. Two-way binds the field state's value with the UI control's value
107
+ * 2. Binds additional forms related state on the field state to the UI control (disabled, required, etc.)
108
+ * 3. Relays relevant events on the control to the field state (e.g. marks touched on blur)
109
+ * 4. Provides a fake `NgControl` that implements a subset of the features available on the
110
+ * reactive forms `NgControl`. This is provided to improve interoperability with controls
111
+ * designed to work with reactive forms. It should not be used by controls written for signal
112
+ * forms.
113
+ *
114
+ * @category control
115
+ * @experimental 21.0.0
116
+ */
117
+ declare class FormField<T> {
118
+ readonly element: HTMLElement;
119
+ readonly injector: Injector;
120
+ readonly formField: i0.InputSignal<FieldTree<T>>;
121
+ readonly state: i0.Signal<[T] extends [_angular_forms.AbstractControl<any, any, any>] ? CompatFieldState<T, string | number> : FieldState<T, string | number>>;
122
+ readonly [_CONTROL]: {
123
+ readonly create: typeof __controlCreate;
124
+ readonly update: typeof _controlUpdate;
125
+ };
126
+ private config;
127
+ /** Any `ControlValueAccessor` instances provided on the host element. */
128
+ private readonly controlValueAccessors;
129
+ /** A lazily instantiated fake `NgControl`. */
130
+ private interopNgControl;
131
+ /** Lazily instantiates a fake `NgControl` for this form field. */
132
+ protected getOrCreateNgControl(): InteropNgControl;
133
+ static ɵfac: i0.ɵɵFactoryDeclaration<FormField<any>, never>;
134
+ static ɵdir: i0.ɵɵDirectiveDeclaration<FormField<any>, "[formField]", never, { "formField": { "alias": "formField"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
135
+ }
136
+
91
137
  /**
92
138
  * Sets a value for the {@link MetadataKey} for this field.
93
139
  *
@@ -377,7 +423,7 @@ type AsyncValidationResult<E extends ValidationError = ValidationError> = Valida
377
423
  * @category types
378
424
  * @experimental 21.0.0
379
425
  */
380
- type FieldTree<TModel, TKey extends string | number = string | number> = (() => [TModel] extends [AbstractControl] ? CompatFieldState<TModel, TKey> : FieldState<TModel, TKey>) & ([TModel] extends [AbstractControl] ? object : [TModel] extends [Array<infer U>] ? ReadonlyArrayLike<MaybeFieldTree<U, number>> : TModel extends Record<string, any> ? Subfields<TModel> : object);
426
+ type FieldTree<TModel, TKey extends string | number = string | number> = (() => [TModel] extends [AbstractControl] ? CompatFieldState<TModel, TKey> : FieldState<TModel, TKey>) & ([TModel] extends [AbstractControl] ? object : [TModel] extends [ReadonlyArray<infer U>] ? ReadonlyArrayLike<MaybeFieldTree<U, number>> : TModel extends Record<string, any> ? Subfields<TModel> : object);
381
427
  /**
382
428
  * The sub-fields that a user can navigate to from a `FieldTree<TModel>`.
383
429
  *
@@ -482,7 +528,7 @@ interface FieldState<TValue, TKey extends string | number = string | number> ext
482
528
  /**
483
529
  * The {@link Field} directives that bind this field to a UI control.
484
530
  */
485
- readonly fieldBindings: Signal<readonly Field<unknown>[]>;
531
+ readonly formFieldBindings: Signal<readonly (Field<unknown> | FormField<unknown>)[]>;
486
532
  /**
487
533
  * Reads a metadata value from the field.
488
534
  * @param key The metadata key to read.
@@ -559,7 +605,7 @@ type CompatSchemaPath<TControl extends AbstractControl, TPathKind extends PathKi
559
605
  *
560
606
  * @experimental 21.0.0
561
607
  */
562
- type SchemaPathTree<TModel, TPathKind extends PathKind = PathKind.Root> = ([TModel] extends [AbstractControl] ? CompatSchemaPath<TModel, TPathKind> : SchemaPath<TModel, SchemaPathRules.Supported, TPathKind>) & (TModel extends AbstractControl ? unknown : TModel extends Array<any> ? unknown : TModel extends Record<string, any> ? {
608
+ type SchemaPathTree<TModel, TPathKind extends PathKind = PathKind.Root> = ([TModel] extends [AbstractControl] ? CompatSchemaPath<TModel, TPathKind> : SchemaPath<TModel, SchemaPathRules.Supported, TPathKind>) & (TModel extends AbstractControl ? unknown : TModel extends ReadonlyArray<any> ? unknown : TModel extends Record<string, any> ? {
563
609
  [K in keyof TModel]: MaybeSchemaPathTree<TModel[K], PathKind.Child>;
564
610
  } : unknown);
565
611
  /**
@@ -692,7 +738,7 @@ type TreeValidator<TValue, TPathKind extends PathKind = PathKind.Root> = LogicFn
692
738
  *
693
739
  * @template TValue The type of value stored in the field being validated
694
740
  * @template TPathKind The kind of path being validated (root field, child field, or item of an array)
695
- *
741
+ * @see [Signal Form Validation](/guide/forms/signals/validation)
696
742
  * @category types
697
743
  * @experimental 21.0.0
698
744
  */
@@ -938,22 +984,6 @@ declare function standardSchemaError(issue: StandardSchemaV1.Issue, options: Wit
938
984
  * @experimental 21.0.0
939
985
  */
940
986
  declare function standardSchemaError(issue: StandardSchemaV1.Issue, options?: ValidationErrorOptions): WithoutField<StandardSchemaValidationError>;
941
- /**
942
- * Create a custom error associated with the target field
943
- * @param obj The object to create an error from
944
- *
945
- * @category validation
946
- * @experimental 21.0.0
947
- */
948
- declare function customError<E extends Partial<ValidationError.WithField>>(obj: WithField<E>): CustomValidationError;
949
- /**
950
- * Create a custom error
951
- * @param obj The object to create an error from
952
- *
953
- * @category validation
954
- * @experimental 21.0.0
955
- */
956
- declare function customError<E extends Partial<ValidationError.WithField>>(obj?: E): WithoutField<CustomValidationError>;
957
987
  /**
958
988
  * Common interface for all validation errors.
959
989
  *
@@ -962,6 +992,8 @@ declare function customError<E extends Partial<ValidationError.WithField>>(obj?:
962
992
  * It's also used by the creation functions to create an instance
963
993
  * (e.g. `requiredError`, `minError`, etc.).
964
994
  *
995
+ * @see [Signal Form Validation](guide/forms/signals/validation)
996
+ * @see [Signal Form Validation Errors](guide/forms/signals/validation#validation-errors)
965
997
  * @category validation
966
998
  * @experimental 21.0.0
967
999
  */
@@ -999,30 +1031,9 @@ declare namespace ValidationError {
999
1031
  */
1000
1032
  interface WithoutField extends ValidationError {
1001
1033
  /** The field associated with this error. */
1002
- readonly field?: never;
1034
+ readonly fieldTree?: never;
1003
1035
  }
1004
1036
  }
1005
- /**
1006
- * A custom error that may contain additional properties
1007
- *
1008
- * @category validation
1009
- * @experimental 21.0.0
1010
- */
1011
- declare class CustomValidationError implements ValidationError {
1012
- /** Brand the class to avoid Typescript structural matching */
1013
- private __brand;
1014
- /**
1015
- * Allow the user to attach arbitrary other properties.
1016
- */
1017
- [key: PropertyKey]: unknown;
1018
- /** Identifies the kind of error. */
1019
- readonly kind: string;
1020
- /** The field associated with this error. */
1021
- readonly fieldTree: FieldTree<unknown>;
1022
- /** Human readable error message. */
1023
- readonly message?: string;
1024
- constructor(options?: ValidationErrorOptions);
1025
- }
1026
1037
  /**
1027
1038
  * Internal version of `NgValidationError`, we create this separately so we can change its type on
1028
1039
  * the exported version to a type union of the possible sub-classes.
@@ -1160,7 +1171,7 @@ type NgValidationError = RequiredValidationError | MinValidationError | MaxValid
1160
1171
  interface SignalFormsConfig {
1161
1172
  /** A map of CSS class names to predicate functions that determine when to apply them. */
1162
1173
  classes?: {
1163
- [className: string]: (state: Field<unknown>) => boolean;
1174
+ [className: string]: (state: Field<unknown> | FormField<unknown>) => boolean;
1164
1175
  };
1165
1176
  }
1166
1177
  /**
@@ -1192,7 +1203,7 @@ interface Predicate {
1192
1203
  *
1193
1204
  * Consider the following example:
1194
1205
  *
1195
- * ```
1206
+ * ```ts
1196
1207
  * const s = schema(p => {
1197
1208
  * disabled(p.data);
1198
1209
  * applyWhen(p.next, ({valueOf}) => valueOf(p.data) === 1, s);
@@ -1560,8 +1571,8 @@ declare class FieldNodeState {
1560
1571
  * Marks this specific field as not touched.
1561
1572
  */
1562
1573
  markAsUntouched(): void;
1563
- /** The {@link Field} directives that bind this field to a UI control. */
1564
- readonly fieldBindings: i0.WritableSignal<readonly Field<unknown>[]>;
1574
+ /** The {@link FormField} directives that bind this field to a UI control. */
1575
+ readonly formFieldBindings: i0.WritableSignal<readonly (Field<unknown> | FormField<unknown>)[]>;
1565
1576
  constructor(node: FieldNode);
1566
1577
  /**
1567
1578
  * Whether this field is considered dirty.
@@ -1635,8 +1646,8 @@ declare class FieldSubmitState {
1635
1646
  * and is still in the process of submitting.
1636
1647
  */
1637
1648
  readonly selfSubmitting: WritableSignal<boolean>;
1638
- /** Server errors that are associated with this field. */
1639
- readonly serverErrors: WritableSignal<readonly ValidationError.WithField[]>;
1649
+ /** Submission errors that are associated with this field. */
1650
+ readonly submissionErrors: WritableSignal<readonly ValidationError.WithField[]>;
1640
1651
  constructor(node: FieldNode);
1641
1652
  /**
1642
1653
  * Whether this form is currently in the process of being submitted.
@@ -1652,8 +1663,8 @@ interface ValidationState {
1652
1663
  */
1653
1664
  rawSyncTreeErrors: Signal<ValidationError.WithField[]>;
1654
1665
  /**
1655
- * The full set of synchronous errors for this field, including synchronous tree errors and server
1656
- * errors. Server errors are considered "synchronous" because they are imperatively added. From
1666
+ * The full set of synchronous errors for this field, including synchronous tree errors and submission
1667
+ * errors. Submission errors are considered "synchronous" because they are imperatively added. From
1657
1668
  * the perspective of the field state they are either there or not, they are never in a pending
1658
1669
  * state.
1659
1670
  */
@@ -1786,7 +1797,7 @@ declare class FieldNode implements FieldState<unknown> {
1786
1797
  get disabledReasons(): Signal<readonly DisabledReason[]>;
1787
1798
  get hidden(): Signal<boolean>;
1788
1799
  get readonly(): Signal<boolean>;
1789
- get fieldBindings(): Signal<readonly Field<unknown>[]>;
1800
+ get formFieldBindings(): Signal<readonly (Field<unknown> | FormField<unknown>)[]>;
1790
1801
  get submitting(): Signal<boolean>;
1791
1802
  get name(): Signal<string>;
1792
1803
  get max(): Signal<number | undefined> | undefined;
@@ -2239,7 +2250,7 @@ declare function form<TModel>(model: WritableSignal<TModel>, schemaOrOptions: Sc
2239
2250
  * ```ts
2240
2251
  * const nameForm = form(signal({first: '', last: ''}), (name) => {
2241
2252
  * required(name.first);
2242
- * validate(name.last, ({value}) => !/^[a-z]+$/i.test(value()) ? customError({kind: 'alphabet-only'}) : undefined);
2253
+ * validate(name.last, ({value}) => !/^[a-z]+$/i.test(value()) ? {kind: 'alphabet-only'} : undefined);
2243
2254
  * });
2244
2255
  * nameForm().valid(); // false
2245
2256
  * nameForm().value.set({first: 'John', last: 'Doe'});
@@ -2344,10 +2355,10 @@ declare function applyWhenValue<TValue, TNarrowed extends TValue>(path: SchemaPa
2344
2355
  */
2345
2356
  declare function applyWhenValue<TValue>(path: SchemaPath<TValue>, predicate: (value: TValue) => boolean, schema: NoInfer<SchemaOrSchemaFn<TValue>>): void;
2346
2357
  /**
2347
- * Submits a given `FieldTree` using the given action function and applies any server errors
2348
- * resulting from the action to the field. Server errors returned by the `action` will be integrated
2358
+ * Submits a given `FieldTree` using the given action function and applies any submission errors
2359
+ * resulting from the action to the field. Submission errors returned by the `action` will be integrated
2349
2360
  * into the field as a `ValidationError` on the sub-field indicated by the `field` property of the
2350
- * server error.
2361
+ * submission error.
2351
2362
  *
2352
2363
  * @example
2353
2364
  * ```ts
@@ -2370,7 +2381,7 @@ declare function applyWhenValue<TValue>(path: SchemaPath<TValue>, predicate: (va
2370
2381
  * ```
2371
2382
  *
2372
2383
  * @param form The field to submit.
2373
- * @param action An asynchronous action used to submit the field. The action may return server
2384
+ * @param action An asynchronous action used to submit the field. The action may return submission
2374
2385
  * errors.
2375
2386
  * @template TModel The data type of the field being submitted.
2376
2387
  *
@@ -2389,5 +2400,5 @@ declare function submit<TModel>(form: FieldTree<TModel>, action: (form: FieldTre
2389
2400
  */
2390
2401
  declare function schema<TValue>(fn: SchemaFn<TValue>): Schema<TValue>;
2391
2402
 
2392
- export { CustomValidationError, EmailValidationError, FIELD, Field, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MaxLengthValidationError, MaxValidationError, MetadataKey, MetadataReducer, MinLengthValidationError, MinValidationError, NgValidationError, PATTERN, PathKind, PatternValidationError, REQUIRED, RequiredValidationError, SchemaPathRules, StandardSchemaValidationError, ValidationError, apply, applyEach, applyWhen, applyWhenValue, createManagedMetadataKey, createMetadataKey, customError, emailError, form, maxError, maxLengthError, metadata, minError, minLengthError, patternError, provideSignalFormsConfig, requiredError, schema, standardSchemaError, submit };
2403
+ export { EmailValidationError, FIELD, FORM_FIELD, Field, FormField, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MaxLengthValidationError, MaxValidationError, MetadataKey, MetadataReducer, MinLengthValidationError, MinValidationError, NgValidationError, PATTERN, PathKind, PatternValidationError, REQUIRED, RequiredValidationError, SchemaPathRules, StandardSchemaValidationError, ValidationError, apply, applyEach, applyWhen, applyWhenValue, createManagedMetadataKey, createMetadataKey, emailError, form, maxError, maxLengthError, metadata, minError, minLengthError, patternError, provideSignalFormsConfig, requiredError, schema, standardSchemaError, submit };
2393
2404
  export type { AsyncValidationResult, ChildFieldContext, CompatFieldState, CompatSchemaPath, Debouncer, DisabledReason, FieldContext, FieldState, FieldTree, FieldValidator, FormOptions, ItemFieldContext, ItemType, LogicFn, MaybeFieldTree, MaybeSchemaPathTree, MetadataSetterType, OneOrMany, ReadonlyArrayLike, RootFieldContext, Schema, SchemaFn, SchemaOrSchemaFn, SchemaPath, SchemaPathTree, SignalFormsConfig, Subfields, SubmittedStatus, TreeValidationResult, TreeValidator, ValidationResult, ValidationSuccess, Validator, WithField, WithOptionalField, WithoutField };
package/types/forms.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license Angular v21.1.0-next.4
3
- * (c) 2010-2025 Google LLC. https://angular.dev/
2
+ * @license Angular v21.1.0-rc.0
3
+ * (c) 2010-2026 Google LLC. https://angular.dev/
4
4
  * License: MIT
5
5
  */
6
6
 
@@ -1073,7 +1073,7 @@ type ɵFormArrayRawValue<T extends AbstractControl<any>> = ɵTypedOrUntyped<T, A
1073
1073
  * the `FormArray` directly, as that result in strange and unexpected behavior such
1074
1074
  * as broken change detection.
1075
1075
  *
1076
- * @see [FormArray: Dynamic, Homogenous Collections](guide/forms/typed-forms#formcontrol-getting-started)
1076
+ * @see [FormArray: Dynamic, Homogenous Collections](guide/forms/typed-forms#formarray-dynamic-homogenous-collections)
1077
1077
  * @see [Creating dynamic forms](guide/forms/reactive-forms#creating-dynamic-forms)
1078
1078
  *
1079
1079
  * @publicApi
@@ -2769,9 +2769,7 @@ declare abstract class AbstractControl<TValue = any, TRawValue extends TValue =
2769
2769
  *
2770
2770
  * @usageNotes
2771
2771
  *
2772
- * ### Reference to a ValidatorFn
2773
- *
2774
- * ```
2772
+ * ```ts
2775
2773
  * // Reference to the RequiredValidator
2776
2774
  * const ctrl = new FormControl<string | null>('', Validators.required);
2777
2775
  * ctrl.removeValidators(Validators.required);
@@ -2809,9 +2807,7 @@ declare abstract class AbstractControl<TValue = any, TRawValue extends TValue =
2809
2807
  *
2810
2808
  * @usageNotes
2811
2809
  *
2812
- * ### Reference to a ValidatorFn
2813
- *
2814
- * ```
2810
+ * ```ts
2815
2811
  * // Reference to the RequiredValidator
2816
2812
  * const ctrl = new FormControl<number | null>(0, Validators.required);
2817
2813
  * expect(ctrl.hasValidator(Validators.required)).toEqual(true)
@@ -2867,6 +2863,9 @@ declare abstract class AbstractControl<TValue = any, TRawValue extends TValue =
2867
2863
  * * `emitEvent`: When true or not supplied (the default), the `events`
2868
2864
  * observable emits a `TouchedChangeEvent` with the `touched` property being `true`.
2869
2865
  * When false, no events are emitted.
2866
+ *
2867
+ * @see [Managing form control state](guide/forms/reactive-forms#managing-form-control-state)
2868
+ *
2870
2869
  */
2871
2870
  markAsTouched(opts?: {
2872
2871
  onlySelf?: boolean;
@@ -2881,6 +2880,9 @@ declare abstract class AbstractControl<TValue = any, TRawValue extends TValue =
2881
2880
  * * `emitEvent`: When true or not supplied (the default), the `events`
2882
2881
  * observable emits a `PristineChangeEvent` with the `pristine` property being `false`.
2883
2882
  * When false, no events are emitted.
2883
+ *
2884
+ * @see [Managing form control state](guide/forms/reactive-forms#managing-form-control-state)
2885
+ *
2884
2886
  */
2885
2887
  markAllAsDirty(opts?: {
2886
2888
  emitEvent?: boolean;
@@ -2894,6 +2896,9 @@ declare abstract class AbstractControl<TValue = any, TRawValue extends TValue =
2894
2896
  * * `emitEvent`: When true or not supplied (the default), the `events`
2895
2897
  * observable emits a `TouchedChangeEvent` with the `touched` property being `true`.
2896
2898
  * When false, no events are emitted.
2899
+ *
2900
+ * @see [Managing form control state](guide/forms/reactive-forms#managing-form-control-state)
2901
+ *
2897
2902
  */
2898
2903
  markAllAsTouched(opts?: {
2899
2904
  emitEvent?: boolean;
@@ -2915,6 +2920,9 @@ declare abstract class AbstractControl<TValue = any, TRawValue extends TValue =
2915
2920
  * * `emitEvent`: When true or not supplied (the default), the `events`
2916
2921
  * observable emits a `TouchedChangeEvent` with the `touched` property being `false`.
2917
2922
  * When false, no events are emitted.
2923
+ *
2924
+ * @see [Managing form control state](guide/forms/reactive-forms#managing-form-control-state)
2925
+ *
2918
2926
  */
2919
2927
  markAsUntouched(opts?: {
2920
2928
  onlySelf?: boolean;
@@ -2935,6 +2943,9 @@ declare abstract class AbstractControl<TValue = any, TRawValue extends TValue =
2935
2943
  * * `emitEvent`: When true or not supplied (the default), the `events`
2936
2944
  * observable emits a `PristineChangeEvent` with the `pristine` property being `false`.
2937
2945
  * When false, no events are emitted.
2946
+ *
2947
+ * @see [Managing form control state](guide/forms/reactive-forms#managing-form-control-state)
2948
+ *
2938
2949
  */
2939
2950
  markAsDirty(opts?: {
2940
2951
  onlySelf?: boolean;
@@ -2958,6 +2969,9 @@ declare abstract class AbstractControl<TValue = any, TRawValue extends TValue =
2958
2969
  * * `emitEvent`: When true or not supplied (the default), the `events`
2959
2970
  * observable emits a `PristineChangeEvent` with the `pristine` property being `true`.
2960
2971
  * When false, no events are emitted.
2972
+ *
2973
+ * @see [Managing form control state](guide/forms/reactive-forms#managing-form-control-state)
2974
+ *
2961
2975
  */
2962
2976
  markAsPristine(opts?: {
2963
2977
  onlySelf?: boolean;
@@ -3064,6 +3078,9 @@ declare abstract class AbstractControl<TValue = any, TRawValue extends TValue =
3064
3078
  * `valueChanges` and `events`
3065
3079
  * observables emit events with the latest status and value when the control is updated.
3066
3080
  * When false, no events are emitted.
3081
+ *
3082
+ * @see [Understanding propagation control](guide/forms/reactive-forms#understanding-event-emission)
3083
+ *
3067
3084
  */
3068
3085
  updateValueAndValidity(opts?: {
3069
3086
  onlySelf?: boolean;
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license Angular v21.1.0-next.4
3
- * (c) 2010-2025 Google LLC. https://angular.dev/
2
+ * @license Angular v21.1.0-rc.0
3
+ * (c) 2010-2026 Google LLC. https://angular.dev/
4
4
  * License: MIT
5
5
  */
6
6