Search code examples
javascriptangularinputform-control

How to set value in a loop of formControl?


I have a mat-table and one of the column heading is having an edit icon/button, on click of which all the values of the third column are converted into input fields. I just want to set the same value in the input fields as well.

I have tried this.

 <ng-container matColumnDef="amount">
    <th mat-header-cell *matHeaderCellDef>Amount
        <button mat-icon-button (click)="onEditClick(datasource)">
            <mat-icon style="cursor: pointer;"  class="ml-2 mr-2" >edit</mat-icon>
        </button>
    </th>
    <td mat-cell *matCellDef="let row; let i=index;">
       <ng-container *ngIf="isActual">{{row.amount || "-- --"}}</ng-container>
        <mat-form-field *ngIf="isEditMonth" class="example-full-width month-textbox" appearance="outline">
            <input matInput type="text" [formControl]="amountField" (change)="onAmountChanged($event,row)" [ngModel]=row.amount>
        </mat-form-field>
    </td>
</ng-container>

//ts code

  amountField = new FormControl('', Validators.compose([Validators.min(0)]));

  onEditClick() {
    if (this.isEditMonth) {
      this.loadCharges();
      this.isEditMonth = false;
      this.isActual = true;
    }
    else {
      this.isEditMonth = true;
      this.isActual = false;      
    }
  }

Please check my stackbiltz code. enter link description here


Solution

  • For this you have to dynamically build a group of FormControls for the available length of your array.

    HTML

    <form [formGroup]="elementForm" id="ngForm" #form="ngForm">
      <div [formGroupName]="'amountFields'">
        <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
    
          <ng-container matColumnDef="unit">
            <th mat-header-cell *matHeaderCellDef>Unit.</th>
            <td mat-cell *matCellDef="let element">{{ element.unit }}</td>
          </ng-container>
    
          <ng-container matColumnDef="accountNo">
            <th mat-header-cell *matHeaderCellDef>Account No.</th>
            <td mat-cell *matCellDef="let element">{{ element.accountNo }}</td>
          </ng-container>
    
          <ng-container matColumnDef="amount">
            <th mat-header-cell *matHeaderCellDef>
              Amount
              <button mat-icon-button (click)="onEditClick()">
                <mat-icon style="cursor: pointer;" class="ml-2 mr-2">edit</mat-icon>
              </button>
            </th>
    
            <td mat-cell *matCellDef="let element">
              <ng-container *ngIf="isActual">{{ element.amount }}</ng-container>
              <mat-form-field
                class="example-full-width month-textbox"
                appearance="outline"
                *ngIf="isEditMonth">
                <input
                  matInput
                  appearence="fill"
                  type="text"
                  [formControlName]="element.accountNo"
                  (change)="onAmountChanged($event, element)"
                />
              </mat-form-field>
            </td>
          </ng-container>
    
          <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
          <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
        </table>
      </div>
    </form>
    

    TS

    import { OnInit, Component, VERSION } from '@angular/core';
    import {
      FormGroup,
      FormControl,
      Validators,
      FormBuilder,
    } from '@angular/forms';
    
    export interface PeriodicElement {
      accountNo: string;
      unit: number;
      amount: number;
    }
    
    const ELEMENT_DATA: PeriodicElement[] = [
      { unit: 1, accountNo: 'Hydrogen', amount: 20 },
      { unit: 2, accountNo: 'Helium', amount: 10 },
      { unit: 3, accountNo: 'Lithium', amount: 50 },
    ];
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
    })
    export class AppComponent implements OnInit {
      constructor(private formBuilder: FormBuilder) {}
      name = 'Angular ' + VERSION.major;
      isActual: boolean = true;
      isEditMonth: boolean = false;
      amountFieldsFormGroup: FormGroup = this.formBuilder.group([]);
      public elementForm: FormGroup = new FormGroup({
        amountFields: this.amountFieldsFormGroup,
      });
    
      amountField = new FormControl('', Validators.compose([Validators.min(0)]));
    
      displayedColumns: string[] = ['unit', 'accountNo', 'amount'];
      dataSource = ELEMENT_DATA;
    
      ngOnInit() {
        this.createFormValues();
        console.log(this.elementForm);
      }
    
      private createFormValues(): void {
        this.dataSource.forEach((element: PeriodicElement) => {
          this.amountFieldsFormGroup.addControl(
            element.accountNo,
            this.createElementFormControl(element.amount)
          );
        });
      }
    
      private createElementFormControl(amount: number): FormControl {
        return new FormControl(
          { value: amount, disabled: false },
          { validators: Validators.nullValidator }
        );
      }
    
      onEditClick() {
        if (this.isEditMonth) {
          this.isEditMonth = false;
          this.isActual = true;
        } else {
          this.isEditMonth = true;
          this.isActual = false;
        }
      }
    
      onAmountChanged(e, elem) {}
    }
    

    Change it for your needs...

    Thanks.