1

I have a complicated FormGroup which contains multiple FormControls, FormGroups and FormArrys.

I need to implement form reset to its initial value. However, the initial value may be retrieved from the server. Meaning that I get some kind of JSON then parse it into my FormGroup and I need to save this state to be able to reset everything to what it was before.

FormGroup.reset() or FormGroupDirective.resetForm() just reset the values of controls while not changing the FormArrays length.

I have following structure of FormGroup

formGroup: FormGroup = this.fb.group({
    unitNames: this.fb.array([this.createName()], Validators.required),
    types: this.fb.array([], Validators.required),
    addresses: this.fb.array([]),
    requisites: this.fb.array([]),
    note: [null],
    mediaContent: this.fb.array([])
});

Where each FormArray is filled with complex FormGroups after JSON fetch.

What is the best way to save the initial state and then recover it on form reset?


For now I'm trying to do it that way

resetForm() {
    this.formGroupDirective.resetForm();
    this.formGroup = this.fb.group({
        unitNames: this.fb.array([this.createName()], Validators.required),
        types: this.fb.array([], Validators.required),
        addresses: this.fb.array([]),
        requisites: this.fb.array([]),
        note: [null],
        mediaContent: this.fb.array([])
    });

    this.patchDeep(this.savedUnit);
    this.resetPopup.close();
}

patchDeep(unit) {
    if (unit.unitNames && unit.unitNames.length > 0) {
        unit.unitNames.forEach((unitName, i) => {
            this.names.setControl(i, this.createName(unitName));
        });
    }

    if (unit.unitAddresses && unit.unitAddresses.length > 0) {
        unit.unitAddresses.forEach((addressGroup, i) => {
            this.addresses.setControl(i, this.fs.createAddress(addressGroup));
        });
    }
}

However, this approach requires manual FormArray reset to 0 so that no extra values will be present and doesn't seem right.


Approximate JSON

{
    unitNames: [
        {
            id: 1,
            nameTypeId: 3,
            value: 'Unit 1'
        },
        {
            id: 2,
            nameTypeId: 1,
            value: 'Unit Alias'
        }
    ],
    types: [
        {
            unitTypeId: 3,
            unitCode: 3131,
            unitNote: 'sample text'
        }
    ],
    requisites: [
        {
            country: 'UK',
            city: 'London',
            build: 'B122/1',
            phones: [
                {
                    phoneType: 32,
                    value: '992-123-1'
                },
                {
                    phoneType: 1,
                    value: '123'
                }
            ]
        }
    ],
    note: 'Hello world'
}
Sergey
  • 7,184
  • 13
  • 42
  • 85
  • Just reuse the logic you use when you "retrieve the values from the server" after `resetForm` – Roberto Zvjerković Jan 29 '19 at 09:04
  • I now I can, but I feel like there is another better way. Because I have to create my formGroup from scratch to not to go through all FormArrays manually what causes the need to recreate reference (I store a reference to the form object in other place to have easy access. This reference is lost during formGroup recreation) – Sergey Jan 29 '19 at 09:09
  • can you provide your json object? – Ami Vyas Jan 31 '19 at 07:40
  • @AmiVyas added. That's an approximate structure, but it has all the properties of the real one. Simple key-value pair that's equal to FormControl. FormArray out of FormGroups. – Sergey Jan 31 '19 at 18:47

1 Answers1

0

I'm having exact problem right now. Since you asked it almost 3 years ago, I'm really curious what solution you ended up with.

For me, seems like there are two solutions (both equally bad):

  1. Recreate (rebind) root formGroup - this causes you to lost reference to orignal formGroup, but it also breaks all the subscriptions to valueChanges, and in my case I additionaly run into trouble with change detection not running and other things (e.g. some selects or checkboxes being enabled even after I disabled root formGroup).

  2. Go through each formArray and manually clean it using someFormArray.removeAt() or use someFormArray.clear() and then add elements again with someFormArray.push(). - this looks like the most commonly used idea. It may be acceptable when you have small form that won't grow, and you can just access that someFormArray directly. But when you have big complex form, you can try writing some method which may use recursion to find formArrays but it may be painful to write something universal that will work for every case of nested formGroups and formArrays.


In 2016 someone requested form.reset() to also clean formArray length, but someone from Angular team closed that issue suggesting to recreate (rebind) root formGroup. See: https://github.com/angular/angular/issues/10960

Here are similar questions on stack but the answers sum up to the two solutions I proposed:

How do I clear the FormArray in Angular Reactive Forms

restore the modal original state in FormArray on "Cancel Change" button clicked in angular5

How to clear the FormArray values in angular reactive form?

FormArray length does not reset by form.reset()

How to reset formarray to one item in angular

FormArray in Angular Reactive Form not resetting on form submit