diff --git a/packages/forms/src/model.ts b/packages/forms/src/model.ts index 23b066866c..71d6ad0f6b 100644 --- a/packages/forms/src/model.ts +++ b/packages/forms/src/model.ts @@ -1895,6 +1895,43 @@ export class FormArray extends AbstractControl { }); } + /** + * Remove all controls in the `FormArray`. + * + * @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(): void { + if (this.controls.length < 1) return; + this._forEachChild((control: AbstractControl) => control._registerOnCollectionChange(() => {})); + this.controls.splice(0); + this.updateValueAndValidity(); + } + /** @internal */ _syncPendingControls(): boolean { let subtreeUpdated = this.controls.reduce((updated: boolean, child: AbstractControl) => { diff --git a/packages/forms/test/form_array_spec.ts b/packages/forms/test/form_array_spec.ts index 2a94c68a44..fe89f77238 100644 --- a/packages/forms/test/form_array_spec.ts +++ b/packages/forms/test/form_array_spec.ts @@ -59,6 +59,20 @@ import {of } from 'rxjs'; expect(a.controls).toEqual([c1, c3]); }); + it('should support clearing', () => { + a.push(c1); + a.push(c2); + a.push(c3); + + a.clear(); + + expect(a.controls).toEqual([]); + + a.clear(); + + expect(a.controls).toEqual([]); + }); + it('should support inserting', () => { a.push(c1); a.push(c3); diff --git a/tools/public_api_guard/forms/forms.d.ts b/tools/public_api_guard/forms/forms.d.ts index f76319ff16..f9e915c065 100644 --- a/tools/public_api_guard/forms/forms.d.ts +++ b/tools/public_api_guard/forms/forms.d.ts @@ -170,6 +170,7 @@ export declare class FormArray extends AbstractControl { readonly length: number; constructor(controls: AbstractControl[], validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null); at(index: number): AbstractControl; + clear(): void; getRawValue(): any[]; insert(index: number, control: AbstractControl): void; patchValue(value: any[], options?: {