Search code examples
htmlangulartypescriptangular6formarray

Not able to store dynamic FormArray in FormGroup


I have a FormGroup which has three FormControl fields and one FormArray fields as shown in the figure below. The requirement is to take the manager name from user and once add button is pressed, manager details should be displayed in table. In table a remove button is provided, when remove button is pressed manager should be removed form the table and list. When the form is submitted list of managers should be saved. Everything works fine except formArray logic.

enter image description here

I tried to find a solution to this online (followed various links:- https://alligator.io/angular/reactive-forms-formarray-dynamic-fields/, Angular 4 Form FormArray Add a Button to add or delete a form input row), but did not helped much. There is not much material on how to store formArray in formGroup. Please suggest.

Below is my code, please have a look:-

1. manager-create-modal.component.html

<div>
    <form [formGroup]="createForm" (ngSubmit)="onFormCreation()">
        <div class="row">
             <div class="column">
               <div class="form-inline">
                 <div class="form-group">
                    <label for="remote_access_method">Remote Access Method: <font color="orange"> *</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>
                      <input type="text" size='38' class="form-control" formControlName="remote_access_method" >
                 </div>
                </div>
               <br>
               <div class="form-inline">
                 <div class="form-group">
                    <label for="status">Current Status: <font color="orange"> *</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>
                    <input type="text" size='38' class="form-control" formControlName="status">
                 </div>
               </div>
               <br>
               <div class="form-inline">
                 <div class="form-group">
                   <label for="secregid">Registration ID:<font color="orange"> *</font> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>
                   <input type="text" size='38' class="form-control" formControlName="secregid">
                 </div>
               </div>
               <br><br>
               <div class="form-inline">
                 <div class="form-group">
                    <br><br>
                    <div formArrayName="manager_formArray">
                      Enter name: <input type="text" class="form-control" formControlName="MgrName" size='50' >&nbsp;&nbsp;
                      <button type="button" class="btn btn-primary btn-sm" (click)="addPM()">Add</button>
                        <br><br>
                        <table class="table table-hover">
                          <tr><th>#</th><th>Manager Name</th><th>Remove</th></tr>
                          <tr *ngFor="let pm of createForm.get('manager_formArray').value; let id = index">
                              <td>{{id+1}}</td>
                              <td>{{pm.MgrName}}</td>
                              <td>
                                <span class="table-remove">
                                  <button type="button" class="btn btn-primary btn-sm" (click)="removeMgr(id)">Remove</button>
                                </span>
                              </td>
                          </tr>
                        </table>
                    </div>
                 </div>
               </div>
              </div>
              <br>
            </div>
            <br><br>
            <div class="form-group">
            <button class="btn btn-primary">Submit</button>
        </div>
    </form>
</div>

2. manager-create-modal.component.ts

    import { Component, OnInit } from '@angular/core';
    import { FormGroup, FormBuilder, FormArray, FormControl, Validators } from '@angular/forms';


    @Component({
      selector: 'app-manager-create-modal',
      templateUrl: './manager-create-modal.component.html',
      styleUrls: ['./manager-create-modal.component.css']
    })
    export class ManagerCreateModalComponent implements OnInit {

      createForm: FormGroup;
      manager_formArray: FormArray;
      remote_access_method: FormControl;
      status: FormControl;
      secregid: FormControl;

      constructor(private formBuilder: FormBuilder) { }

      createFormControls(){
        this.remote_access_method = new FormControl('');
        this.status = new FormControl('');
        this.secregid  = new FormControl('');
        this.manager_formArray = new FormArray([ this.createItem() ]);
      }

      createItem(): FormGroup {
          return this.formBuilder.group({
            MgrName: ''
          });
      }

      createFormVariables(){
          this.createForm = new FormGroup({
            remote_access_method  : this.remote_access_method,
            status  : this.status,
            secregid   : this.secregid,
            manager_formArray: this.manager_formArray,
          })
      }

      ngOnInit() {
          this.createFormControls();
          this.createFormVariables();
      }

      addPM(mgr: any): void {
          console.log("inside addPM");
          this.manager_formArray.push(this.formBuilder.group({MgrName:''}));
          console.log("list after addition:"+this.manager_formArray.value);

          for(let i = 0; i < this.manager_formArray.length; i++) {
             console.log(this.manager_formArray.at(i).value);
          }
      }

      get managerFormArray() {
       return this.manager_formArray.get('MgrName') as FormArray;
     }

     onFormCreation(){
       console.log("success")
     }
    }

The manager name is not displayed in the table and I keep on getting below error:-

ERROR Error: Cannot find control with path: 'manager_formArray -> MgrName' at _throwError (forms.js:1731) at setUpControl (forms.js:1639) at FormGroupDirective.push../node_modules/@angular/forms/fesm5/forms.js.FormGroupDirective.addControl (forms.js:4456) at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName._setUpControl (forms.js:4961) at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName.ngOnChanges (forms.js:4911) at checkAndUpdateDirectiveInline (core.js:9031) at checkAndUpdateNodeInline (core.js:10299) at checkAndUpdateNode (core.js:10261) at debugCheckAndUpdateNode (core.js:10894) at debugCheckDirectivesFn (core.js:10854) inside addPM manager-create-modal.component.ts:50 list after addition:[object Object],[object Object] manager-create-modal.component.ts:53 {MgrName: ""} manager-create-modal.component.ts:53 {MgrName: ""}

I even don't understand why elements are not getting added to manager_formArray. Please help me out.


Solution

  • You have a few issues. First of all, it is better to move the Input which adds more FormGroups to your FormArray outside of the <div formArrayName="manager_formArray">- element. I created a new FormControl this.mgrNameInput = new FormControl(''); for this reason (see StackBlitz for more details).

    You also need to add the message to the new entry when you press the Add-button, calling the addPM()-method:

    addPM(){ // removed the argument, using the controller inside the method instead.
        this.manager_formArray.push(this.formBuilder.group({MgrName:this.mgrNameInput.value}));
        this.mgrNameInput.reset(); // reset the input field.
    }
    

    I also added the remove-method when removing an entry.

    removeMgr(index: number){
        this.manager_formArray.removeAt(index);
    }
    

    Please check the StackBlitz for the complete example