angularformsangular-reactive-formsformarrayformgroups

How to push collection of formgroup into formArray


I have a form in a steper (cdk) that works fine and I'm refactoring it to make it dynamic. My goal is to use json at the end to generate the form content.

Right now I have the following code:

export class StepperFormsComponent implements OnInit {
  private readonly fb: FormBuilder = inject(FormBuilder);

    stepperForm: FormGroup;

    get formArray() {
      return this.stepperForm.get('steps') as FormArray;
    }

  ngOnInit(): void {
    this.initForm();
    this.addInitialControlsToForm();
  }

  initForm(): void {
    this.stepperForm = this.fb.group({
      steps: this.fb.array([]),
    });
  }

  addInitialControlsToForm(): void {
    const stepsArray = this.formArray;

    const formData = [
      this.fb.group({
        userInfo: ['', Validators.required],
      }),
      this.fb.group({
        carInfo: ['', Validators.required],
      }),
      this.fb.group({
        configEnvironments: ['', Validators.required],
        configAditionalInfo: ['', Validators.required],
      }),
    ];

    formData.forEach(data => {
      stepsArray.push(data);
    });
  }


}

the previous code work but what I'm trying to archieve right now is not working. I need to make this form more dynamic.

So the idea is to create the method getFormControlFields(), with formGroupFields object and Iterate over all properties in the model using the for to push in formGroupFields,


export class StepperFormsComponent implements OnInit {
  private readonly fb: FormBuilder = inject(FormBuilder);

  getControls(): AbstractControl[] {
    return (<FormArray>this.stepperForm.get('steps')).controls;
  }

  ngOnInit(): void {
    this.initForm();

    console.log('formArray', this.formArray.controls.length); // display 1 instead of 3
    console.log('formArray step 1',  this.formArray.get([0])?.value); // works fine
    console.log('formArray step 2',  this.formArray.get([1])?.value); // undefined

  }

  initForm(): void {
    const formGroupFields = this.getFormControlsFields();

    this.stepperForm = this.fb.group({
      steps: this.fb.array([formGroupFields]),
    });
  }

  getFormControlsFields() {
    const formGroupFields: FormGroup[] = [];

    const formData = [
      this.fb.group({
        userInfo: ['', Validators.required],
      }),
      this.fb.group({
        carInfo: ['', Validators.required],
      }),
      this.fb.group({
        configEnvironments: ['', Validators.required],
        configAditionalInfo: ['', Validators.required],
      }),
    ];

    formData.forEach(data => {
      formGroupFields.push(data);
    });

    return formGroupFields;
  }
}

So my question is how do I push my formgroup inside the formArray ?

Thanks


Solution

  • The function (getFormControlsFields) returns an array, so you need to directly input the returned value and remove the wrapper array ([formGroupFields])

      initForm(): void {
        const formGroupFields = this.getFormControlsFields();
    
        this.stepperForm = this.fb.group({
          steps: this.fb.array(formGroupFields), // <- changed here!
        });
      }
    

    Also we can simplify the code to. Based on the code you shared, maybe I am wrong!

      getFormControlsFields() {
        return [
          this.fb.group({
            userInfo: ['', Validators.required],
          }),
          this.fb.group({
            carInfo: ['', Validators.required],
          }),
          this.fb.group({
            configEnvironments: ['', Validators.required],
            configAditionalInfo: ['', Validators.required],
          }),
        ];
      }