Lint
Lint

Reputation: 935

Adding a dynamic row in a table in Angular

I want to add a row when I click on Add button, the table exists in a Reactive form.

Here's the structure that I'm talking about

Here's how I tried html file

<tr *ngFor='let row of tableRows'>
    <div fxLayout="row" fxLayoutAlign="start center" fxFlex="1 0 auto">
        <td fxFlex="22">
            <mat-form-field appearance="outline" fxFlex="100" class="pr-4">
                <mat-label>Product </mat-label>
                <mat-select [(ngModel)]="tableRows.productId" required>
                    <mat-option *ngFor='let product of productList' [value]="product.productId">
                        {{product.name}}
                    </mat-option>
                </mat-select>
            </mat-form-field>
        </td>
        <td fxFlex="15">
            <mat-form-field appearance="outline" fxFlex="100" class="pr-4">
                <mat-label>Price </mat-label>
                <input type='number' matInput [(ngModel)]="tableRows.price" name="" id="" placeholder="Price" required>
            </mat-form-field>
        </td>
        <td fxFlex="15">
            <mat-form-field appearance="outline" fxFlex="100" class="pr-4">
                <mat-label>Loan Term </mat-label>
                <mat-select [(ngModel)]="tableRows.loanTermId" required>
                    <mat-option *ngFor='let loanTerm of loanTermList' [value]="loanTerm.loanTermId">
                        {{loanTerm.numberOfMonths}}
                    </mat-option>
                </mat-select>
            </mat-form-field>
        </td>
        <td fxFlex="15">
            <mat-form-field appearance="outline" fxFlex="100" class="pr-4">
                <mat-label>Quantity </mat-label>
                <input type='number' matInput [(ngModel)]="tableRows.quantity" name="" id="" placeholder="Quantity" required>
            </mat-form-field>
        </td>
        <td fxFlex="15">
            <mat-form-field appearance="outline" fxFlex="100" class="pr-4">
                <mat-label>Deposit </mat-label>
                <input type='number' matInput [(ngModel)]="tableRows.deposit" name="" id="" placeholder="Deposit" required>
            </mat-form-field>
        </td>
        <td fxFlex="15">
            <mat-form-field appearance="outline" fxFlex="100" class="pr-4">
                <mat-label>Total </mat-label>
                <input type='number' matInput [(ngModel)]="tableRows.total" name="" id="" placeholder="Total" required>
            </mat-form-field>
        </td>

and here's how I'm trying in ts file

newRow = { productId: '', price: '', loanTermId: '', quantity: '', deposit: '', total: '' };
tableRows = [{ productId: '', price: '', loanTermId: '', quantity: '', deposit: '', total: '' }];

  addTableRow() {
    this.newRow = { productId: '', price: '', loanTermId: '', quantity: '', deposit: '', total: '' };
    this.tableRows.push(this.newRow)
  }

Hoping that I'd work. I receive the following error in console

ERROR Error: 
      ngModel cannot be used to register form controls with a parent formGroup directive.  Try using
      formGroup's partner directive "formControlName" instead.

Upvotes: 1

Views: 1038

Answers (1)

Sudeep Sagar
Sudeep Sagar

Reputation: 253

You cannot use ngModel with FormControl. Instead Use FormControlName and FormArray. In component,ts file

 import { FormBuilder, FormGroup, FormArray, FormControl } from '@angular/forms';

In constructor:: constructor(private fb: FormBuilder) { }

    ngOnInit() {

    /* Initiate the form structure */
    this.productForm = this.fb.group({
      pData: this._fb.array([])
    })
    this.addFormDetails();
  }

   addFormDetails {
     this.rowDataArray.push(this.BuildFormDynamic(data_from_backend));
   }

    get formData() { // use getter method to get the row array
       return this.productForm.get('pData') as FormArray;
  }

Access data_from_backend and assign it here, if black then no data will show in HTML, if have value then values will be displayed on HTML

    BuildFormDynamic(data_from_backend): FormGroup {
    return this._fb.group({
      abc: [data_from_backend.abc],
      def: [data_from_backend.def],
      ghi: [data_from_backend.ghi],
      jkl: [data_from_backend.jkl],
      mno: [data_from_backend.mno],
      pqr: [data_from_backend.pqr]
    });
  }

In HTML, access these valiable using FOrmControlName Name your form elementproductForm: FormGroup; Same form name should be given in html file like this::

    `<form [formGroup]="productForm">
      <div formArrayName="pData">
    <div *ngFor="let item of formData.controls; let pointIndex=index" [formGroupName]="pointIndex">
    <label>
      Test Name: <input formControlName="abc" />
    </label>
<button type="button" (click)="deleteFormRows(pointIndex)">Delete Selling Point</button>
    </div>
<button type="button" (click)="addFormRows()">Add Selling Point</button>
  </div>
    </form>`

To add and Delete rows

 addFormRows() {
    this.formData.push(this.fb.group({point:''}));
  }
deleteFormRows(index) {
    this.formData.removeAt(index);
  }

This is just an example, customise it according to your requirement. Lemme know if any issues

Upvotes: 3

Related Questions