Remove all items from a FormArray in Angular

AngularAngular2 Forms

Angular Problem Overview


I have a form array inside a FormBuilder and I am dynamically changing forms, i.e. on click load data from application 1 etc.

The issue I am having is that all the data loads in but the data in the FormArray stays and just concats the old items with new.

How do I clear that FormArray to only have the new items.

I've tried this

const control2 = <FormArray>this.registerForm.controls['other_Partners'];
control2.setValue([]);

but it doesn't work.

Any ideas?

ngOnInit(): void {
  this.route.params.subscribe(params => {
    if (params['id']) {
      this.id = Number.parseInt(params['id']);
    } else { this.id = null;}
  });
  if (this.id != null && this.id != NaN) {
    alert(this.id);
    this.editApplication();
    this.getApplication(this.id);
  } else {
    this.newApplication();
  }
}

onSelect(Editedapplication: Application) {
  this.router.navigate(['/apply', Editedapplication.id]);
}

editApplication() {
  this.registerForm = this.formBuilder.group({
    id: null,
    type_of_proposal: ['', Validators.required],
    title: ['', [Validators.required, Validators.minLength(5)]],
    lead_teaching_fellow: ['', [Validators.required, Validators.minLength(5)]],
    description: ['', [Validators.required, Validators.minLength(5)]],
    status: '',
    userID: JSON.parse(localStorage.getItem('currentUser')).username,
    contactEmail: JSON.parse(localStorage.getItem('currentUser')).email,
    forename: JSON.parse(localStorage.getItem('currentUser')).firstname,
    surname: JSON.parse(localStorage.getItem('currentUser')).surname,
    line_manager_discussion: true,
    document_url: '',
    keywords: ['', [Validators.required, Validators.minLength(5)]],
    financial_Details: this.formBuilder.group({
      id: null,
      buying_expertise_description: ['', [Validators.required, Validators.minLength(2)]],
      buying_expertise_cost: ['', [Validators.required]],
      buying_out_teaching_fellow_cost: ['', [Validators.required]],
      buying_out_teaching_fellow_desc: ['', [Validators.required, Validators.minLength(2)]],
      travel_desc: ['', [Validators.required, Validators.minLength(2)]],
      travel_cost: ['', [Validators.required]],
      conference_details_desc: ['', [Validators.required, Validators.minLength(2)]],
      conference_details_cost: ['', [Validators.required]],
    }),

    partners: this.formBuilder.array([
        //this.initEditPartner(),
        //this.initEditPartner()
        // this.initMultiplePartners(1)
      ]
    ),
    other_Partners: this.formBuilder.array([
      //this.initEditOther_Partners(),
    ])
  });
}

getApplication(id) {
  this.applicationService.getAppById(id, JSON.parse(localStorage.getItem('currentUser')).username)
    .subscribe(Response => {
      if (Response.json() == false) {
        this.router.navigateByUrl('/');
      } else {
        this.application = Response.json();
        for (var i = 0; i < this.application.partners.length;i++) {
          this.addPartner();
        }
        for (var i = 0; i < this.application.other_Partners.length; i++) {
          this.addOther_Partner();
        }

        this.getDisabledStatus(Response.json().status);
        (<FormGroup>this.registerForm) .setValue(Response.json(), { onlySelf: true });
      }
    });
}

ngOnInit is not being called on click

Angular Solutions


Solution 1 - Angular

I had same problem. There are two ways to solve this issue.

Preserve subscription

You can manually clear each FormArray element by calling the removeAt(i) function in a loop.

clearFormArray = (formArray: FormArray) => {
  while (formArray.length !== 0) {
    formArray.removeAt(0)
  }
}

> The advantage to this approach is that any subscriptions on your formArray, such as that registered with formArray.valueChanges, will not be lost.

See the FormArray documentation for more information.


Cleaner method (but breaks subscription references)

You can replace whole FormArray with a new one.

clearFormArray = (formArray: FormArray) => {
  formArray = this.formBuilder.array([]);
}

> This approach causes an issue if you're subscribed to the formArray.valueChanges observable! If you replace the FromArray with a new array, you will lose the reference to the observable that you're subscribed to.

Solution 2 - Angular

Or you can simply clear the controls

this.myForm= {
     name: new FormControl(""),
     desc: new FormControl(""),
     arr: new FormArray([])
}

Add something array

const arr = <FormArray>this.myForm.controls.arr;
arr.push(new FormControl("X"));

Clear the array

const arr = <FormArray>this.myForm.controls.arr;
arr.controls = [];

When you have multiple choices selected and clear, sometimes it doesn't update the view. A workaround is to add

arr.removeAt(0)
UPDATE

A more elegant solution to use form arrays is using a getter at the top of your class and then you can access it.

get inFormArray(): FormArray {
    this.myForm.get('inFormArray') as FormArray;
}

And to use it in a template

<div *ngFor="let c of inFormArray; let i = index;" [formGroup]="i">
other tags...
</div>

Reset:

inFormArray.reset();

Push:

inFormArray.push(new FormGroup({}));

Remove value at index: 1

inFormArray.removeAt(1);
UPDATE 2:

Get partial object, get all errors as JSON and many other features, use the NaoFormsModule

Solution 3 - Angular

As of Angular 8+ you can use clear() to remove all controls in the FormArray:

const arr = new FormArray([
   new FormControl(),
   new FormControl()
]);
console.log(arr.length);  // 2

arr.clear();
console.log(arr.length);  // 0

For previous versions the recommended way is:

while (arr.length) {
   arr.removeAt(0);
}

https://angular.io/api/forms/FormArray#clear

Solution 4 - Angular

Angular 8

simply use clear() method on formArrays :

(this.invoiceForm.controls['other_Partners'] as FormArray).clear();

Solution 5 - Angular

Warning!

The Angular v6.1.7 FormArray documentation says:

> To change the controls in the array, use the push, insert, or removeAt > methods in FormArray itself. These methods ensure the controls are > properly tracked in the form's hierarchy. Do not modify the array of > AbstractControls used to instantiate the FormArray directly, as that > result in strange and unexpected behavior such as broken change > detection.

Keep this in mind if you are using the splice function directly on the controls array as one of the answer suggested.

Use the removeAt function.

  while (formArray.length !== 0) {
    formArray.removeAt(0)
  }

Solution 6 - Angular

Angular v4.4 if you need to save the same reference to the instance of FormArray try this:

purgeForm(form: FormArray) {
  while (0 !== form.length) {
    form.removeAt(0);
  }
}

Solution 7 - Angular

You can easily define a getter for your array and clear it as follows:

  formGroup: FormGroup    
  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.formGroup = this.fb.group({
      sliders: this.fb.array([])
    })
  }
  get sliderForms() {
    return this.formGroup.get('sliders') as FormArray
  }

  clearAll() {
    this.formGroup.reset()
    this.sliderForms.clear()
  }

Solution 8 - Angular

Use FormArray.clear() to remove all the elements of an array in a FormArray

Solution 9 - Angular

Simply

formArray.clear()

would be enough

Solution 10 - Angular

Update: Angular 8 finally got method to clear the Array FormArray.clear()

Solution 11 - Angular

Since Angular 8 you can use this.formArray.clear() to clear all values in form array. It's a simpler and more efficient alternative to removing all elements one by one

Solution 12 - Angular

Provided the data structure for what you will be replacing the information in the array with matches what is already there you can use patchValue

https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html#!#reset-anchor

> patchValue(value: any[], {onlySelf, emitEvent}?: {onlySelf?: boolean, > emitEvent?: boolean}) : void Patches the value of the FormArray. It > accepts an array that matches the structure of the control, and will > do 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.

const arr = new FormArray([
   new FormControl(),
   new FormControl()
]);
console.log(arr.value);   // [null, null]
arr.patchValue(['Nancy']);
console.log(arr.value);   // ['Nancy', null]

Alternatively you could use reset

> reset(value?: any, {onlySelf, emitEvent}?: {onlySelf?: boolean, > emitEvent?: boolean}) : void Resets the FormArray. This means by > default: > > The array and all descendants are marked pristine The array and all > descendants are marked untouched The value of all descendants will be > null or null maps You can also reset to a specific form state by > passing in an array of states that matches the structure of the > control. The state can be a standalone value or a form state object > with both a value and a disabled status. >

this.arr.reset(['name', 'last name']);
console.log(this.arr.value);  // ['name', 'last name']

> > OR >

this.arr.reset([   {value: 'name', disabled: true},   'last' ]);
console.log(this.arr.value);  // ['name', 'last name']
console.log(this.arr.get(0).status);  // 'DISABLED'

Here's a forked Plunker demo from some earlier work of mine demoing a very simple utilization of each.

Solution 13 - Angular

I never tried using formArray, I have always worked with FormGroup, and you can remove all controls using:

Object.keys(this.formGroup.controls).forEach(key => {
          this.formGroup.removeControl(key);
        });

being formGroup an instance of FormGroup.

Solution 14 - Angular

To keep the code clean I have created the following extension method for anyone using Angular 7 and below. This can also be used to extend any other functionality of Reactive Forms.

import { FormArray } from '@angular/forms';

declare module '@angular/forms/src/model' {
  interface FormArray {
    clearArray: () => FormArray;
  }
}

FormArray.prototype.clearArray = function () {
  const _self = this as FormArray;
  _self.controls = [];
  _self.setValue([]);
  _self.updateValueAndValidity();
  return _self;
}

Solution 15 - Angular

(this.questionForm.controls['answers'] as FormArray).clear();

Solution 16 - Angular

I am very late but I found some other way where you don't need to have loops. you can reset array by setting array control to empty.

Below code will reset your array.

this.form.setControl('name', this.fb.array([]))

Solution 17 - Angular

While loop will take long time to delete all items if array has 100's of items. You can empty both controls and value properties of FormArray like below.

clearFormArray = (formArray: FormArray) => { formArray.controls = []; formArray.setValue([]); }

Solution 18 - Angular

If you are using Angular 7 or a previous version and you dont' have access to the clear() method, there is a way to achieve that without doing any loop:

yourFormGroup.controls.youFormArrayName = new FormArray([]);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKarl O&#39;ConnorView Question on Stackoverflow
Solution 1 - AngularCamelDView Answer on Stackoverflow
Solution 2 - AngularPian0_M4nView Answer on Stackoverflow
Solution 3 - AngularcrappylimeView Answer on Stackoverflow
Solution 4 - AngularMajiDView Answer on Stackoverflow
Solution 5 - AngularzgueView Answer on Stackoverflow
Solution 6 - AngularAlex DzeikoView Answer on Stackoverflow
Solution 7 - AngularM.RezaView Answer on Stackoverflow
Solution 8 - AngularAnu PriyaView Answer on Stackoverflow
Solution 9 - AngularParinda RajapakshaView Answer on Stackoverflow
Solution 10 - Angularnightingale2k1View Answer on Stackoverflow
Solution 11 - AngularNikita KorbaView Answer on Stackoverflow
Solution 12 - AngularsilentsodView Answer on Stackoverflow
Solution 13 - AngularPianisimoView Answer on Stackoverflow
Solution 14 - AngularDanielok1993View Answer on Stackoverflow
Solution 15 - AngularNdiaga GUEYEView Answer on Stackoverflow
Solution 16 - AngularAsifView Answer on Stackoverflow
Solution 17 - Angularuser3067875View Answer on Stackoverflow
Solution 18 - Angularrom5jpView Answer on Stackoverflow