Search code examples
angularangular-reactive-formsangular2-forms

angular 7 reactive forms: dynamically add / remove input fields for each input field in the form


I have to dynamically create a form with data received from the server with the option of adding and removing input fields for each existing input fields.

This is the data i receive from the server

documents = [{id: 1, service_item_id: 311101, name: 'document 1'}, {id: 2, service_item_id: 311102,, name: 'document 2'}, {id: 3, service_item_id: 311103,, name: 'document 3'}, {id: 4, service_item_id: 311104,, name: 'document 4'}]

I have created a function to create the form

createControls(controls) {
    console.log(controls);
    for (let control of controls) {
        const newFormControl = new FormControl();
        this.myForm.addControl(control.service_item_id, newFormControl);
    }
}

this.createControls(this.documents);

And in the Html I have created this

<form [formGroup]="myForm" (ngSubmit)="submitForm()">
    <div *ngFor="let c of documentation; let index = index">
        <label>
            {{ c.name}}
        </label>
        <input type="number" [formControlName]="c.service_item_id" [placeholder]="c.name" />
        <button class="btn btn-primary btn-sm" (click)="add(c.service_item_id)">Add</button>
        <button class="btn btn-primary btn-sm" (click)="remove(c.service_item_id, index)">Remove</button>
    </div>
    <button type="submit" class="btn btn-primary btn-small">Submit</button>
</form>

My add and remove functions are

add(item): void {
    (this.myForm.get(item) as FormArray).push(
      this.fb.control(null)
    );
  }

  remove(item, index) {
    (this.myForm.get(item) as FormArray).removeAt(index);
  }

Only the form is getting created but add and remove buttons are not working.

Please do help me resolve this issue. Thanks in advance


Solution

  • I think what will work best for your situation is to use FormArray. With FormArray you can push and remove items just like you would do with a normal array

      myForm = this.fb.group({
        documents: this.fb.array([])
      });
    
      get documentsControl(): FormArray {
        return this.myForm.get("documents") as FormArray;
      }
      documents = [
        { id: 1, service_item_id: 311101, name: "document 1" },
        { id: 2, service_item_id: 311102, name: "document 2" },
        { id: 3, service_item_id: 311103, name: "document 3" },
        { id: 4, service_item_id: 311104, name: "document 4" }
      ];
      ngOnInit() {
        this.documents.forEach(document =>
          this.documentsControl.push(
            this.fb.group({
              id: [document.id],
              name: [document.name],
              service_item_id: [document.service_item_id]
            })
          )
        );
      }
      constructor(private fb: FormBuilder) {}
      submitForm() {}
      add() {
        this.documentsControl.push(
          this.fb.group({
            id: [null],
            name: [null],
            service_item_id: [null]
          })
        );
      }
      remove(index) {
        this.documentsControl.removeAt(index);
      }
    

    to add items we use push while to remove items we use removeAt

    Below is the html

    <form [formGroup]="myForm" (ngSubmit)="submitForm()">
        <ng-container formArrayName='documents'>
          <div *ngFor="let c of documentsControl.controls; let index = index" [formGroupName]='index'>
            <label>
                {{ c.value.name}}
            </label>
            <input type="number" formControlName="service_item_id" placeholder="name" />
            <button class="btn btn-primary btn-sm" (click)="add()">Add</button>
            <button class="btn btn-primary btn-sm" (click)="remove(index)">Remove</button>
        </div>
        </ng-container>
        <button type="submit" class="btn btn-primary btn-small">Submit</button>
    </form>
    

    Edit

    To add items below there clicked button we can implement insert()

      insert(index) {
        const serviceItenId = this.documentsControl.controls[index].get('service_item_id').value
        this.documentsControl.insert(
          index + 1,
          this.fb.group({
            id: [null],
            name: [null],
            service_item_id: [serviceItenId]
          })
        );
      }
    

    I have updated the below Demo to reflect this

    See Demo