Angular 2: Iterate over reactive form controls

Angular

Angular Problem Overview


I would like to markAsDirty all the controls inside of a FormGroup.

Angular Solutions


Solution 1 - Angular

Found out that Object.keys can handle this..

    Object.keys(this.form.controls).forEach(key => {
      this.form.get(key).markAsDirty();
    });

For Angular 8+, use the following (based on Michelangelo answer):

    Object.keys(this.form.controls).forEach(key => {
      this.form.controls[key].markAsDirty();
    });

Solution 2 - Angular

For what it's worth, there's another way to do this without having to use Object.keys(...) magic:

for (const field in this.form.controls) { // 'field' is a string

  const control = this.form.get(field); // 'control' is a FormControl  

}

Solution 3 - Angular

The accepted answer is correct for a flat form structure, but does not completely answer the original question. A web page may require nested FormGroups and FormArrays, and we must account for this to create a robust solution.

public markControlsDirty(group: FormGroup | FormArray): void {
    Object.keys(group.controls).forEach((key: string) => {
        const abstractControl = group.controls[key];

        if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
            this.markControlsDirty(abstractControl);
        } else {
            abstractControl.markAsDirty();
        }
    });
}

Solution 4 - Angular

Seems that get function is not working anymore for retrieving specific values in your form in Angular 8, so this is how I solved it based on the answer of @Liviu Ilea.

for (const field in this.myForm.controls) { // 'field' is a string
  console.log(this.myForm.controls[field].value);
}

Solution 5 - Angular

Using @Marcos answer I created a function that can be called passing a formGroup as parameter and it marks every formGroup children controls to dirty, just to make it usable from more places around the code putting it inside a service, for example.

public touchAllFormFields(formGroup: FormGroup): void {
    Object.keys(formGroup.controls).forEach((key) => {
        formGroup.get(key).markAsDirty();
    });
}

hope it helps ;)

Solution 6 - Angular

    Object.keys( this.registerForm.controls).forEach(key => {
       this.registerForm.controls[key].markAsDirty();
    });

Solution 7 - Angular

This is what working for me

private markFormGroupTouched(formGroup: FormGroup) {
  Object.keys(formGroup.controls).forEach((key) => {
    const control = formGroup.controls[key];
    control.markAsDirty();
    if ((control instanceof FormGroup)) {
      this.markFormGroupTouched(control);
    }
  });
}

Solution 8 - Angular

Here, is my solution to your problem, I'm using for loop with an index, hope this helps.

    for (const key of Object.keys(this.forms.controls)) {
      this.forms.controls[key].markAsDirty();
    }

Solution 9 - Angular

I was looking for a similar solution for a project with multiple forms having file uploads. I needed to create a Form Data object and copy all fields of form in multiple pages. This worked fine for Angular 11.

const formData : FormData = new FormData();

 Object.keys(this.staffForm.controls).forEach(key => {
      console.log("Control Key => "+key); 
      console.log("Control Val => "+this.staffForm.controls[key].value); 
      formData.append(key, this.staffForm.controls[key].value);
    });

Solution 10 - Angular

I create this function to make it* I have a control with name 'order', and pass index to him.

{"conditionGroups": [
   {
     "order": null,
     "conditions": []
   }
  ]
}


updateFormData() {
    const control = <FormArray>this.form.controls['conditionGroups'];  
    control.value.map((x,index)=>{
    x.order = index; 
 })

Solution 11 - Angular

Based on @Keenan Diggs answer I wrote a generic function to traverse a flat or nested form, which accepts an operation to be performed against each form control:

export function traverseForm(
    form: FormGroup | FormArray, 
    fn: ((c: AbstractControl, name: string, path: string) => void),
    initialPath: string = '') {
  Object.keys(form.controls).forEach((key: string) => {
    const abstractControl = form.controls[key];
    const path = initialPath ? (initialPath + '.' + key) : key;
    fn(abstractControl, key, path);
    if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
        traverseForm(abstractControl, fn, path);
    }
  });
} 

To be used like this:

const markAsDirty = (ctrl: AbstractControl) => {
   if (!(abstractControl instanceof FormGroup) && !(abstractControl instanceof FormArray)) {
      abstractControl.markAsDirty();
   }
}
traverseForm(form, markAsDirty);

Solution 12 - Angular

If you don't want to loop over your form control, you can use this way also...

export class NewComponent implements OnInit {
  @ViewChild(ClrForm) clrForm: ClrForm;

  form: FormGroup;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    this.buildForm();
  }

  onFormSubmit() {
    if (this.form.invalid) {
      this.clrForm.markAsDirty();
      return;
    }
  }

  private buildForm() {
    this.form = this.formBuilder.group({
      sender: [null, [Validators.required]],
      sentAt: ['', [Validators.required]]
    });
  }
}
<form clrForm [formGroup]="form" (submit)="onFormSubmit()">
  <div class="clr-form-control clr-row">
    <label for="sender" class="clr-control-label clr-col-4">Sender</label>
    <div class="clr-control-container clr-col-8">
      <app-custom-form-control formControlName="sender"></app-custom-form-control>
    </div>
  </div>

  <clr-date-container>
    <label class="clr-col-4">Data wysłania</label>
    <input
      type="date"
      class="clr-col-8"
      clrDate
      formControlName="sentAt"
    />
  </clr-date-container>

  <input type="submit" value="Save" />
</form>

Solution 13 - Angular

you can loop over a FormGroup's children using the _forEachChild() method of a formGroup. This worked for me for patching values in nested formGroups.

this.myForm.myFormGroup._forEachChild( control => {
  control.markAsDirty();
})    

Solution 14 - Angular

Simple Solution to iterate formGroup controls to get values of each form controls:


formGroup: FormGroup;

this.formGroup = this.formBuilder.group({
      control1: new FormControl('value1'),
      control2: new FormControl(`value2`),
      control3: new FormControl('value3')
    });

Object.keys(this.formGroup.controls).forEach(key => {
      console.log(this.formGroup.controls[key].value)
});

// Output:

value1

value2

value4

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
QuestionMarcos J.C KichelView Question on Stackoverflow
Solution 1 - AngularMarcos J.C KichelView Answer on Stackoverflow
Solution 2 - AngularLiviu IleaView Answer on Stackoverflow
Solution 3 - AngularKeenan DiggsView Answer on Stackoverflow
Solution 4 - AngularMichelangeloView Answer on Stackoverflow
Solution 5 - AngularHugoView Answer on Stackoverflow
Solution 6 - AngularFoadView Answer on Stackoverflow
Solution 7 - AngularomyfishView Answer on Stackoverflow
Solution 8 - AngularMaidenless RuntView Answer on Stackoverflow
Solution 9 - AngularVishal KumarView Answer on Stackoverflow
Solution 10 - AngularJoão Marcos Santos TeixeiraView Answer on Stackoverflow
Solution 11 - AngularAlex CheView Answer on Stackoverflow
Solution 12 - AngularMD. RAKIB HASANView Answer on Stackoverflow
Solution 13 - Angularnatalie dkView Answer on Stackoverflow
Solution 14 - AngularkhizerView Answer on Stackoverflow