8

I have a form in Angular 2 that works with a custom ControlGroup. At the moment, when I submit my form, I pass all the data with the following line to my controller.

(ngSubmit)="updateArtist(artistDetailForm.value)"

The problem is that this passes all values of a form, and if my forms are quite large this feels quite useless. Is there a possibility to only pass the modified (dirty?) values?

hY8vVpf3tyR57Xib
  • 3,574
  • 8
  • 41
  • 86

3 Answers3

10

Declare your form.

this.artistDetailForm= formBuilder.group({......});

Define a function to extract values on submit

// feed me controlGroups

getDirtyValues(cg) {
  let dirtyValues = {};  // initialize empty object
  Object.keys(cg.controls).forEach((c) => {

     let currentControl = cg.find(c);

     if(currentControl.dirty){
        if(currentControl.controls) //check for nested controlGroups
           dirtyValues[c] = getDirtyValues(currentControl);  //recursion for nested controlGroups
        else    
           dirtyValues[c] = currentControl.value;  //simple control
     }

    });
  return dirtyValues;
}

and then do this

(ngSubmit)="updateArtist(getDirtyValues( artistDetailForm ))"

PLUNKER

Ankit Singh
  • 24,525
  • 11
  • 66
  • 89
  • 3
    For Angular 6, you can use `let currentControl = controlGroups.get(c);` to replace `let currentControl = cg.find(c);` if it gives you an error. – Ben Gulapa Jun 05 '18 at 04:01
7

Here's a version that traverse an arbitrary Form structure and gives you the changed values in a nested Map-like structure. Meaning the returned dirty values will be at the same level as the dirty control.

getDirtyValues(
  form: FormGroup | FormArray | FormControl | AbstractControl
): Map<string, any> | any[] | any | undefined {
  if (!form.dirty) {
    return;
  }

  if (form instanceof FormControl) {
    return form.value;
  }

  if (form instanceof FormGroup) {
    const result = new Map();
    for (const [key, control] of Object.entries(form.controls)) {
      const nestedResult = this.getDirtyValues(control);
      if (nestedResult) {
        result.set(key, this.getDirtyValues(control));
      }
    }

    return result;
  }

  if (form instanceof FormArray) {
    const result = new Array();
    form.controls.forEach(control => {
      const nestedResult = this.getDirtyValues(control);
      if (nestedResult) {
        result.push(nestedResult);
      }
    });

    return result;
  }

  throw new Error('Form must be a FromGroup, FormArray or FormControl.');
}
Snæbjørn
  • 10,322
  • 14
  • 65
  • 124
6

With the new changes to the Angular Forms I've slightly modified the accepted answer, so it works. Decided to share if anyone is interested. (using Angular 4+)

getDirtyValues(form: any) {
        let dirtyValues = {};

        Object.keys(form.controls)
            .forEach(key => {
                const currentControl = form.controls[key];

                if (currentControl.dirty) {
                    if (currentControl.controls)
                        dirtyValues[key] = this.getDirtyValues(currentControl);
                    else
                        dirtyValues[key] = currentControl.value;
                }
            });

        return dirtyValues;
}
marked-down
  • 9,958
  • 22
  • 87
  • 150
Shirohige
  • 90
  • 3
  • 12