Home > Net >  Dynamically create form fields and map to data model
Dynamically create form fields and map to data model

Time:12-05

I am trying to create functionality that maps some input fields to a model however it needs to be dynamic(there can be multiple repetitions of the image I have below).

The below image shows the design I am following

enter image description here

Explanation of flow

I have an input field called "current vehicle instalment" and a check box below it called "I am settling this account". If I click on the check box it will show 2 additional fields called "Account number" and "Financed by".

Then I have a button called "Add another vehicle instalment".

If I click this button it will add another vehicle input field called "Vehicle instalment 2" as well as another checkbox below it called "I am settling this account". If I click on the check box it will show 2 additional fields called "Account number" and "Financed by" that are related to vehicle 2.

I can have a maximum of 3 vehicles so once I add the 3rd vehicle I will no longer see the "Add another vehicle instalment" button

enter image description here

Here is my code so far

HTML

  <div>
    <form-input [dspRestrictedInput]="{type : 'numeric'}" [formStatus]="formStatus"
      [parentFormGroup]="avafIncomeAndExpensesForm" [data]="formObjVehicleInstalment"
      (onChange)="onValueChanged()"></form-input>
  </div>
  <div>
    <form-checkbox [formStatus]="formStatus" [parentFormGroup]="avafIncomeAndExpensesForm"
      [data]="settlecheckboxObj"> </form-checkbox>
  </div>
  <div *ngIf="showSettlementFields">
    <form-input [formStatus]="formStatus"
      [parentFormGroup]="avafIncomeAndExpensesForm" [data]="formObjAccountNumber"
      (onChange)="onValueChanged()"></form-input>
  </div>
  <div *ngIf="showSettlementFields">
      <form-dropdown [formStatus]="formStatus"
                     [parentFormGroup]="avafIncomeAndExpensesForm"
                     [data]="formObjFinancedBy"
                     (onChange)="onValueChanged()">
      </form-dropdown>
  </div>
  <div (click)="addVehicleInstalment($event)">
    <a><span  ></span></a>
    <h4>Add another vehicle instalment</h4>
  </div>

TS

  onChangeSettlecheckBox(value) {
    if (value == true) {
      //show additional fields when check box is selected
      this.showSettlementFields = true;
    }
  }

  addVehicleInstalment(event) {
    //add next vehicle
    this.isVehicleInstalmentClicked = true;
  }

This is an example model that I must map each vehicle object to

 "existingVehicleAccounts": [
    {
    "instalment": 1000,
    "settle": true,
    "accountNumber": "11111",
    "financedBy": "Bank4"
    },
    {
    "instalment": 2000,
    "settle": false,
    "accountNumber": "22222",
    "financedBy": "Bank2"
    },
    {
    "instalment": 3000,
    "settle": true,
    "accountNumber": "33333",
    "financedBy": "Bank1"
    }
]

I am currently trying to add the next vehicle section in my addVehicleInstalment method. Any suggestions on how I can do this. I think I need to use indexes to identify which vehicle is for which object in my model.

I have added a very generic stackblitz example with just basic HTML functionality as I currently have it

https://stackblitz.com/edit/angular-ngfor-click-index-inhntc?file=src/app/app.component.html,src/app/app.component.ts

CodePudding user response:

you should use FormArray, where every item is a FormGroup:

ngOnInit() {
    this.vehicleForm = new FormGroup({
      vehicleAccounts: new FormArray([]),
    });

    // start with one empty account
    this.addInstalment();
  }

  addInstalment() {
    const vehicleAccount = new FormGroup({
      instalment: new FormControl(),
      settle: new FormControl(false),
      accountNumber: new FormControl(),
      financedBy: new FormControl(),
    });

    this.vehicleAccounts.push(vehicleAccount);
  }

Then, you define a getter to access this array in the template:

get vehicleAccounts() {
    return this.vehicleForm.controls['vehicleAccounts'] as FormArray;
  }

On every button click, you add a new FormGroup to the array and let it display via ngFor.

And this is the template:

<form [formGroup]="vehicleForm" (ngSubmit)="submit()">
  <div formArrayName="vehicleAccounts">
    <div
      *ngFor="let vehicleAccountForm of vehicleAccounts.controls; let i = index"
    >
      <hr />
      <div [formGroup]="vehicleAccountForm">
        <div >
          <label for="current">{{
            i === 0
              ? 'current vehicle instalment'
              : 'vehicle instalment '   (i   1)
          }}</label>
          <input type="text" id="current" formControlName="instalment" />
        </div>
        <input
          type="checkbox"
          id="settling-{{ i }}"
          formControlName="settle"
          (change)="changeSettling($event, i)"
        />
        <label for="settling-{{ i }}">I'm settling this account</label>
        <div *ngIf="vehicleAccountForm.controls['settle'].value">
          <div >
            <label for="accountNumber">account number</label>
            <input
              type="text"
              id="accountNumber"
              formControlName="accountNumber"
            />
          </div>
          <div >
            <label for="financedBy">financed by</label>
            <select id="financedByy" formControlName="financedBy">
              <option value="bank 1">bank 1</option>
              <option value="bank 2">bank 2</option>
              <option value="bank 3">bank 3</option>
              <option value="bank 4">bank 4</option>
            </select>
          </div>
        </div>
      </div>
    </div>
    <hr />
  </div>
  <button
    (click)="addInstalment()"
    [disabled]="vehicleAccounts.length === 3"
    type="button"
  >
    add another vehicle instalment
  </button>
  <button type="submit">submit</button>
</form>

Check the stackblitz example here

  • Related