mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
500 lines
19 KiB
TypeScript
500 lines
19 KiB
TypeScript
|
|
/**
|
||
|
|
* @license
|
||
|
|
* Copyright Google LLC All Rights Reserved.
|
||
|
|
*
|
||
|
|
* Use of this source code is governed by an MIT-style license that can be
|
||
|
|
* found in the LICENSE file at https://angular.io/license
|
||
|
|
*/
|
||
|
|
|
||
|
|
import {AsyncValidatorFn, ValidatorFn} from '../directives/validators';
|
||
|
|
|
||
|
|
import {AbstractControl, AbstractControlOptions, assertAllValuesPresent, assertControlPresent, pickAsyncValidators, pickValidators} from './abstract_model';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Tracks the value and validity state of an array of `FormControl`,
|
||
|
|
* `FormGroup` or `FormArray` instances.
|
||
|
|
*
|
||
|
|
* A `FormArray` aggregates the values of each child `FormControl` into an array.
|
||
|
|
* It calculates its status by reducing the status values of its children. For example, if one of
|
||
|
|
* the controls in a `FormArray` is invalid, the entire array becomes invalid.
|
||
|
|
*
|
||
|
|
* `FormArray` is one of the three fundamental building blocks used to define forms in Angular,
|
||
|
|
* along with `FormControl` and `FormGroup`.
|
||
|
|
*
|
||
|
|
* @usageNotes
|
||
|
|
*
|
||
|
|
* ### Create an array of form controls
|
||
|
|
*
|
||
|
|
* ```
|
||
|
|
* const arr = new FormArray([
|
||
|
|
* new FormControl('Nancy', Validators.minLength(2)),
|
||
|
|
* new FormControl('Drew'),
|
||
|
|
* ]);
|
||
|
|
*
|
||
|
|
* console.log(arr.value); // ['Nancy', 'Drew']
|
||
|
|
* console.log(arr.status); // 'VALID'
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* ### Create a form array with array-level validators
|
||
|
|
*
|
||
|
|
* You include array-level validators and async validators. These come in handy
|
||
|
|
* when you want to perform validation that considers the value of more than one child
|
||
|
|
* control.
|
||
|
|
*
|
||
|
|
* The two types of validators are passed in separately as the second and third arg
|
||
|
|
* respectively, or together as part of an options object.
|
||
|
|
*
|
||
|
|
* ```
|
||
|
|
* const arr = new FormArray([
|
||
|
|
* new FormControl('Nancy'),
|
||
|
|
* new FormControl('Drew')
|
||
|
|
* ], {validators: myValidator, asyncValidators: myAsyncValidator});
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* ### Set the updateOn property for all controls in a form array
|
||
|
|
*
|
||
|
|
* The options object is used to set a default value for each child
|
||
|
|
* control's `updateOn` property. If you set `updateOn` to `'blur'` at the
|
||
|
|
* array level, all child controls default to 'blur', unless the child
|
||
|
|
* has explicitly specified a different `updateOn` value.
|
||
|
|
*
|
||
|
|
* ```ts
|
||
|
|
* const arr = new FormArray([
|
||
|
|
* new FormControl()
|
||
|
|
* ], {updateOn: 'blur'});
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* ### Adding or removing controls from a form array
|
||
|
|
*
|
||
|
|
* To change the controls in the array, use the `push`, `insert`, `removeAt` or `clear` methods
|
||
|
|
* in `FormArray` itself. These methods ensure the controls are properly tracked in the
|
||
|
|
* form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
|
||
|
|
* the `FormArray` directly, as that result in strange and unexpected behavior such
|
||
|
|
* as broken change detection.
|
||
|
|
*
|
||
|
|
* @publicApi
|
||
|
|
*/
|
||
|
|
export class FormArray extends AbstractControl {
|
||
|
|
/**
|
||
|
|
* Creates a new `FormArray` instance.
|
||
|
|
*
|
||
|
|
* @param controls An array of child controls. Each child control is given an index
|
||
|
|
* where it is registered.
|
||
|
|
*
|
||
|
|
* @param validatorOrOpts A synchronous validator function, or an array of
|
||
|
|
* such functions, or an `AbstractControlOptions` object that contains validation functions
|
||
|
|
* and a validation trigger.
|
||
|
|
*
|
||
|
|
* @param asyncValidator A single async validator or array of async validator functions
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
constructor(
|
||
|
|
public controls: AbstractControl[],
|
||
|
|
validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null,
|
||
|
|
asyncValidator?: AsyncValidatorFn|AsyncValidatorFn[]|null) {
|
||
|
|
super(pickValidators(validatorOrOpts), pickAsyncValidators(asyncValidator, validatorOrOpts));
|
||
|
|
this._initObservables();
|
||
|
|
this._setUpdateStrategy(validatorOrOpts);
|
||
|
|
this._setUpControls();
|
||
|
|
this.updateValueAndValidity({
|
||
|
|
onlySelf: true,
|
||
|
|
// If `asyncValidator` is present, it will trigger control status change from `PENDING` to
|
||
|
|
// `VALID` or `INVALID`.
|
||
|
|
// The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
|
||
|
|
// to `true` to allow that during the control creation process.
|
||
|
|
emitEvent: !!this.asyncValidator
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the `AbstractControl` at the given `index` in the array.
|
||
|
|
*
|
||
|
|
* @param index Index in the array to retrieve the control. If `index` is negative, it will wrap
|
||
|
|
* around from the back, and if index is greatly negative (less than `-length`), the result is
|
||
|
|
* undefined. This behavior is the same as `Array.at(index)`.
|
||
|
|
*/
|
||
|
|
at(index: number): AbstractControl {
|
||
|
|
return this.controls[this._adjustIndex(index)];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Insert a new `AbstractControl` at the end of the array.
|
||
|
|
*
|
||
|
|
* @param control Form control to be inserted
|
||
|
|
* @param options Specifies whether this FormArray instance should emit events after a new
|
||
|
|
* control is added.
|
||
|
|
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||
|
|
* `valueChanges` observables emit events with the latest status and value when the control is
|
||
|
|
* inserted. When false, no events are emitted.
|
||
|
|
*/
|
||
|
|
push(control: AbstractControl, options: {emitEvent?: boolean} = {}): void {
|
||
|
|
this.controls.push(control);
|
||
|
|
this._registerControl(control);
|
||
|
|
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||
|
|
this._onCollectionChange();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Insert a new `AbstractControl` at the given `index` in the array.
|
||
|
|
*
|
||
|
|
* @param index Index in the array to insert the control. If `index` is negative, wraps around
|
||
|
|
* from the back. If `index` is greatly negative (less than `-length`), prepends to the array.
|
||
|
|
* This behavior is the same as `Array.splice(index, 0, control)`.
|
||
|
|
* @param control Form control to be inserted
|
||
|
|
* @param options Specifies whether this FormArray instance should emit events after a new
|
||
|
|
* control is inserted.
|
||
|
|
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||
|
|
* `valueChanges` observables emit events with the latest status and value when the control is
|
||
|
|
* inserted. When false, no events are emitted.
|
||
|
|
*/
|
||
|
|
insert(index: number, control: AbstractControl, options: {emitEvent?: boolean} = {}): void {
|
||
|
|
this.controls.splice(index, 0, control);
|
||
|
|
|
||
|
|
this._registerControl(control);
|
||
|
|
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Remove the control at the given `index` in the array.
|
||
|
|
*
|
||
|
|
* @param index Index in the array to remove the control. If `index` is negative, wraps around
|
||
|
|
* from the back. If `index` is greatly negative (less than `-length`), removes the first
|
||
|
|
* element. This behavior is the same as `Array.splice(index, 1)`.
|
||
|
|
* @param options Specifies whether this FormArray instance should emit events after a
|
||
|
|
* control is removed.
|
||
|
|
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||
|
|
* `valueChanges` observables emit events with the latest status and value when the control is
|
||
|
|
* removed. When false, no events are emitted.
|
||
|
|
*/
|
||
|
|
removeAt(index: number, options: {emitEvent?: boolean} = {}): void {
|
||
|
|
// Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
|
||
|
|
let adjustedIndex = this._adjustIndex(index);
|
||
|
|
if (adjustedIndex < 0) adjustedIndex = 0;
|
||
|
|
|
||
|
|
if (this.controls[adjustedIndex])
|
||
|
|
this.controls[adjustedIndex]._registerOnCollectionChange(() => {});
|
||
|
|
this.controls.splice(adjustedIndex, 1);
|
||
|
|
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Replace an existing control.
|
||
|
|
*
|
||
|
|
* @param index Index in the array to replace the control. If `index` is negative, wraps around
|
||
|
|
* from the back. If `index` is greatly negative (less than `-length`), replaces the first
|
||
|
|
* element. This behavior is the same as `Array.splice(index, 1, control)`.
|
||
|
|
* @param control The `AbstractControl` control to replace the existing control
|
||
|
|
* @param options Specifies whether this FormArray instance should emit events after an
|
||
|
|
* existing control is replaced with a new one.
|
||
|
|
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||
|
|
* `valueChanges` observables emit events with the latest status and value when the control is
|
||
|
|
* replaced with a new one. When false, no events are emitted.
|
||
|
|
*/
|
||
|
|
setControl(index: number, control: AbstractControl, options: {emitEvent?: boolean} = {}): void {
|
||
|
|
// Adjust the index, then clamp it at no less than 0 to prevent undesired underflows.
|
||
|
|
let adjustedIndex = this._adjustIndex(index);
|
||
|
|
if (adjustedIndex < 0) adjustedIndex = 0;
|
||
|
|
|
||
|
|
if (this.controls[adjustedIndex])
|
||
|
|
this.controls[adjustedIndex]._registerOnCollectionChange(() => {});
|
||
|
|
this.controls.splice(adjustedIndex, 1);
|
||
|
|
|
||
|
|
if (control) {
|
||
|
|
this.controls.splice(adjustedIndex, 0, control);
|
||
|
|
this._registerControl(control);
|
||
|
|
}
|
||
|
|
|
||
|
|
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||
|
|
this._onCollectionChange();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Length of the control array.
|
||
|
|
*/
|
||
|
|
get length(): number {
|
||
|
|
return this.controls.length;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Sets the value of the `FormArray`. It accepts an array that matches
|
||
|
|
* the structure of the control.
|
||
|
|
*
|
||
|
|
* This method performs strict checks, and throws an error if you try
|
||
|
|
* to set the value of a control that doesn't exist or if you exclude the
|
||
|
|
* value of a control.
|
||
|
|
*
|
||
|
|
* @usageNotes
|
||
|
|
* ### Set the values for the controls in the form array
|
||
|
|
*
|
||
|
|
* ```
|
||
|
|
* const arr = new FormArray([
|
||
|
|
* new FormControl(),
|
||
|
|
* new FormControl()
|
||
|
|
* ]);
|
||
|
|
* console.log(arr.value); // [null, null]
|
||
|
|
*
|
||
|
|
* arr.setValue(['Nancy', 'Drew']);
|
||
|
|
* console.log(arr.value); // ['Nancy', 'Drew']
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* @param value Array of values for the controls
|
||
|
|
* @param options Configure options that determine how the control propagates changes and
|
||
|
|
* emits events after the value changes
|
||
|
|
*
|
||
|
|
* * `onlySelf`: When true, each change only affects this control, and not its parent. Default
|
||
|
|
* is false.
|
||
|
|
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||
|
|
* `valueChanges`
|
||
|
|
* observables emit events with the latest status and value when the control value is updated.
|
||
|
|
* When false, no events are emitted.
|
||
|
|
* The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
|
||
|
|
* updateValueAndValidity} method.
|
||
|
|
*/
|
||
|
|
override setValue(value: any[], options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
|
||
|
|
assertAllValuesPresent(this, false, value);
|
||
|
|
value.forEach((newValue: any, index: number) => {
|
||
|
|
assertControlPresent(this, false, index);
|
||
|
|
this.at(index).setValue(newValue, {onlySelf: true, emitEvent: options.emitEvent});
|
||
|
|
});
|
||
|
|
this.updateValueAndValidity(options);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Patches the value of the `FormArray`. It accepts an array that matches the
|
||
|
|
* structure of the control, and does its best to match the values to the correct
|
||
|
|
* controls in the group.
|
||
|
|
*
|
||
|
|
* It accepts both super-sets and sub-sets of the array without throwing an error.
|
||
|
|
*
|
||
|
|
* @usageNotes
|
||
|
|
* ### Patch the values for controls in a form array
|
||
|
|
*
|
||
|
|
* ```
|
||
|
|
* const arr = new FormArray([
|
||
|
|
* new FormControl(),
|
||
|
|
* new FormControl()
|
||
|
|
* ]);
|
||
|
|
* console.log(arr.value); // [null, null]
|
||
|
|
*
|
||
|
|
* arr.patchValue(['Nancy']);
|
||
|
|
* console.log(arr.value); // ['Nancy', null]
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* @param value Array of latest values for the controls
|
||
|
|
* @param options Configure options that determine how the control propagates changes and
|
||
|
|
* emits events after the value changes
|
||
|
|
*
|
||
|
|
* * `onlySelf`: When true, each change only affects this control, and not its parent. Default
|
||
|
|
* is false.
|
||
|
|
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||
|
|
* `valueChanges` observables emit events with the latest status and value when the control value
|
||
|
|
* is updated. When false, no events are emitted. The configuration options are passed to
|
||
|
|
* the {@link AbstractControl#updateValueAndValidity updateValueAndValidity} method.
|
||
|
|
*/
|
||
|
|
override patchValue(value: any[], options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
|
||
|
|
// Even though the `value` argument type doesn't allow `null` and `undefined` values, the
|
||
|
|
// `patchValue` can be called recursively and inner data structures might have these values, so
|
||
|
|
// we just ignore such cases when a field containing FormArray instance receives `null` or
|
||
|
|
// `undefined` as a value.
|
||
|
|
if (value == null /* both `null` and `undefined` */) return;
|
||
|
|
|
||
|
|
value.forEach((newValue: any, index: number) => {
|
||
|
|
if (this.at(index)) {
|
||
|
|
this.at(index).patchValue(newValue, {onlySelf: true, emitEvent: options.emitEvent});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
this.updateValueAndValidity(options);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Resets the `FormArray` and all descendants are marked `pristine` and `untouched`, and the
|
||
|
|
* value of all descendants to null or null maps.
|
||
|
|
*
|
||
|
|
* You reset to a specific form state by passing in an array of states
|
||
|
|
* that matches the structure of the control. The state is a standalone value
|
||
|
|
* or a form state object with both a value and a disabled status.
|
||
|
|
*
|
||
|
|
* @usageNotes
|
||
|
|
* ### Reset the values in a form array
|
||
|
|
*
|
||
|
|
* ```ts
|
||
|
|
* const arr = new FormArray([
|
||
|
|
* new FormControl(),
|
||
|
|
* new FormControl()
|
||
|
|
* ]);
|
||
|
|
* arr.reset(['name', 'last name']);
|
||
|
|
*
|
||
|
|
* console.log(arr.value); // ['name', 'last name']
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* ### Reset the values in a form array and the disabled status for the first control
|
||
|
|
*
|
||
|
|
* ```
|
||
|
|
* arr.reset([
|
||
|
|
* {value: 'name', disabled: true},
|
||
|
|
* 'last'
|
||
|
|
* ]);
|
||
|
|
*
|
||
|
|
* console.log(arr.value); // ['last']
|
||
|
|
* console.log(arr.at(0).status); // 'DISABLED'
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* @param value Array of values for the controls
|
||
|
|
* @param options Configure options that determine how the control propagates changes and
|
||
|
|
* emits events after the value changes
|
||
|
|
*
|
||
|
|
* * `onlySelf`: When true, each change only affects this control, and not its parent. Default
|
||
|
|
* is false.
|
||
|
|
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||
|
|
* `valueChanges`
|
||
|
|
* observables emit events with the latest status and value when the control is reset.
|
||
|
|
* When false, no events are emitted.
|
||
|
|
* The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
|
||
|
|
* updateValueAndValidity} method.
|
||
|
|
*/
|
||
|
|
override reset(value: any = [], options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
|
||
|
|
this._forEachChild((control: AbstractControl, index: number) => {
|
||
|
|
control.reset(value[index], {onlySelf: true, emitEvent: options.emitEvent});
|
||
|
|
});
|
||
|
|
this._updatePristine(options);
|
||
|
|
this._updateTouched(options);
|
||
|
|
this.updateValueAndValidity(options);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The aggregate value of the array, including any disabled controls.
|
||
|
|
*
|
||
|
|
* Reports all values regardless of disabled status.
|
||
|
|
* For enabled controls only, the `value` property is the best way to get the value of the array.
|
||
|
|
*/
|
||
|
|
override getRawValue(): any[] {
|
||
|
|
return this.controls.map((control: AbstractControl) => control.getRawValue());
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Remove all controls in the `FormArray`.
|
||
|
|
*
|
||
|
|
* @param options Specifies whether this FormArray instance should emit events after all
|
||
|
|
* controls are removed.
|
||
|
|
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||
|
|
* `valueChanges` observables emit events with the latest status and value when all controls
|
||
|
|
* in this FormArray instance are removed. When false, no events are emitted.
|
||
|
|
*
|
||
|
|
* @usageNotes
|
||
|
|
* ### Remove all elements from a FormArray
|
||
|
|
*
|
||
|
|
* ```ts
|
||
|
|
* const arr = new FormArray([
|
||
|
|
* new FormControl(),
|
||
|
|
* new FormControl()
|
||
|
|
* ]);
|
||
|
|
* console.log(arr.length); // 2
|
||
|
|
*
|
||
|
|
* arr.clear();
|
||
|
|
* console.log(arr.length); // 0
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* It's a simpler and more efficient alternative to removing all elements one by one:
|
||
|
|
*
|
||
|
|
* ```ts
|
||
|
|
* const arr = new FormArray([
|
||
|
|
* new FormControl(),
|
||
|
|
* new FormControl()
|
||
|
|
* ]);
|
||
|
|
*
|
||
|
|
* while (arr.length) {
|
||
|
|
* arr.removeAt(0);
|
||
|
|
* }
|
||
|
|
* ```
|
||
|
|
*/
|
||
|
|
clear(options: {emitEvent?: boolean} = {}): void {
|
||
|
|
if (this.controls.length < 1) return;
|
||
|
|
this._forEachChild((control: AbstractControl) => control._registerOnCollectionChange(() => {}));
|
||
|
|
this.controls.splice(0);
|
||
|
|
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Adjusts a negative index by summing it with the length of the array. For very negative indices,
|
||
|
|
* the result may remain negative.
|
||
|
|
* @internal
|
||
|
|
*/
|
||
|
|
private _adjustIndex(index: number): number {
|
||
|
|
return index < 0 ? index + this.length : index;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @internal */
|
||
|
|
override _syncPendingControls(): boolean {
|
||
|
|
let subtreeUpdated = this.controls.reduce((updated: boolean, child: AbstractControl) => {
|
||
|
|
return child._syncPendingControls() ? true : updated;
|
||
|
|
}, false);
|
||
|
|
if (subtreeUpdated) this.updateValueAndValidity({onlySelf: true});
|
||
|
|
return subtreeUpdated;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @internal */
|
||
|
|
override _forEachChild(cb: (c: AbstractControl, index: number) => void): void {
|
||
|
|
this.controls.forEach((control: AbstractControl, index: number) => {
|
||
|
|
cb(control, index);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @internal */
|
||
|
|
override _updateValue(): void {
|
||
|
|
(this as {value: any}).value =
|
||
|
|
this.controls.filter((control) => control.enabled || this.disabled)
|
||
|
|
.map((control) => control.value);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @internal */
|
||
|
|
override _anyControls(condition: (c: AbstractControl) => boolean): boolean {
|
||
|
|
return this.controls.some((control: AbstractControl) => control.enabled && condition(control));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @internal */
|
||
|
|
_setUpControls(): void {
|
||
|
|
this._forEachChild((control: AbstractControl) => this._registerControl(control));
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @internal */
|
||
|
|
override _allControlsDisabled(): boolean {
|
||
|
|
for (const control of this.controls) {
|
||
|
|
if (control.enabled) return false;
|
||
|
|
}
|
||
|
|
return this.controls.length > 0 || this.disabled;
|
||
|
|
}
|
||
|
|
|
||
|
|
private _registerControl(control: AbstractControl) {
|
||
|
|
control.setParent(this);
|
||
|
|
control._registerOnCollectionChange(this._onCollectionChange);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @internal */
|
||
|
|
override _find(name: string|number): AbstractControl|null {
|
||
|
|
return this.at(name as number) ?? null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
interface UntypedFormArrayCtor {
|
||
|
|
new(controls: AbstractControl[],
|
||
|
|
validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null,
|
||
|
|
asyncValidator?: AsyncValidatorFn|AsyncValidatorFn[]|null): UntypedFormArray;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The presence of an explicit `prototype` property provides backwards-compatibility for apps that
|
||
|
|
* manually inspect the prototype chain.
|
||
|
|
*/
|
||
|
|
prototype: FormArray;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* UntypedFormArray is a non-strongly-typed version of @see FormArray.
|
||
|
|
* Note: this is used for migration purposes only. Please avoid using it directly in your code and
|
||
|
|
* prefer `FormControl` instead, unless you have been migrated to it automatically.
|
||
|
|
*/
|
||
|
|
export type UntypedFormArray = FormArray;
|
||
|
|
|
||
|
|
export const UntypedFormArray: UntypedFormArrayCtor = FormArray;
|
||
|
|
|
||
|
|
export const isFormArray = (control: unknown): control is FormArray => control instanceof FormArray;
|