Search code examples
angularangular-formsangular-formbuilder

Submit dynamically generated content as part of a form


I am currently trying to submit synamically generated content from a table within my form. I am using Angular 6 to generate the form, but for the life of me I cannot figure out how to represent the dynamic content of the form within the FormGroup declaration.

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

  accountDetails = [{
    id: 1,
    name: 'Account 1',
    amountHeld: 5453.7,
    amountToTransfer: 0

  },
  {
    id: 2,
    name: 'Account 2',
    amountHeld: 5644.7,
    amountToTransfer: 0

  },
  {
    id: 3,
    name: 'Account 3',
    amountHeld: 42465.7,
    amountToTransfer: 0

  }
  ,{
    id: 4,
    name: 'Account 4',
    amountHeld: 1434.7,
    amountToTransfer: 0

  }
  ]

  transferDetailsForm = new FormGroup({
    transferType: new FormControl("", [Validators.required]),
  });


}


<form name="transferDetailsForm" [formGroup]="transferDetailsForm">
    <div class="row">
        <div class="form-group">

            <label class="required">Choose category of transfer </label>&nbsp;

              <div id="rbTradeCategorySelect" class="form-group" style="padding-left: 20px;">

                <label for="rbMove" class="radio-inline">
                  <input type="radio" value="SaleOrGift" (change)="changeTransferCategory($event)" formControlName="transferType" click-capture />
                  Sale or gift
                </label>&nbsp;

                <label for="rbLease" class="radio-inline">
                  <input type="radio" radio value="Lease" (change)="changeTransferCategory($event)" formControlName="transferType" click-capture />
                  Lease
                </label>&nbsp;
              </div>
            </div>
          </div>
          <table>
            <thead>
              <th>Account Name </th>
              <th>Account Balance</th>
              <th>Amount to Transfer</th>
            </thead>
            <tbody>
              <tr *ngFor='let a of accountDetails'>
                <td>{{a.name}}</td>
                <td>{{a.amountHeld}}</td>
                <td>
                  <input type="hidden" placeholder="{{a.id}}"/>
                  <input type="text" placeholder="{{a.amountToTransfer}}"/>
                </td>
              </tr>
            </tbody>
          </table>
   <button id="btnSubmit" class="btn btn-success btn-lg" (ngSubmit)="transferDetailsForm.valid"
                    click-capture>
                    Submit
                  </button>      
</form>

I have created the following mock up of my form in the hope that someone can help me.

https://stackblitz.com/edit/angular-yzumze


Solution

  • As I mentioned in the comments, you'd have to use FormArray for that. For a more detailed discussion on when to use FormArray vs FormGroup, check out: When to use FormGroup vs. FormArray?

    Now, check out:

    app.component.ts

    ...
    ...
    ...
    transferDetailsForm: FormGroup;
    results: Array<string>;
    
    constructor(
      private formBuilder: FormBuilder,
    ) { }
    
    ngOnInit() {
      this.transferDetailsForm = this.formBuilder.group({
        amountToTransferArray: this.buildFormArray(),
      });
    }
    
    buildFormArray(): FormArray {
      let arr = [];
      this.accountDetails.forEach(details => {
        arr.push([details.amountToTransfer, [Validators.required]]);
      });
    
      return this.formBuilder.array(arr);
    }
    
    get amountToTransferArray(): FormArray {
      return this.transferDetailsForm.get('amountToTransferArray') as FormArray;
    }
    
    onSubmit() {
      const formModel = this.transferDetailsForm.value;
      this.results = formModel;
    }
    

    app.component.html

    <table>
      <thead>
        <th>Account Name </th>
        <th>Account Balance</th>
        <th>Amount to Transfer</th>
      </thead>
      <tbody>
        <tr *ngFor="let a of accountDetails; let index = index">
          <td>{{ a.name }}</td>
          <td>{{ a.amountHeld }}</td>
          <td>
            <input type="hidden" placeholder="{{ a.id }}"/>
            <input type="number" [formControl]="amountToTransferArray.controls[index]"/>
          </td>
        </tr>
      </tbody>
    </table>
    <button id="btnSubmit" class="btn btn-success btn-lg"
      (click)="onSubmit()">
      Submit
    </button>
    

    I've forked your stackblitz and modified it here: https://stackblitz.com/edit/angular-ib3kth