How to Work with Formarray and Angular-Material Table

How to Work with Formarray and Angular-Material Table

I'm using Angular-Material and the component of mat-table, I'm trying to create a form to set some concepts to create a bill, but when I make the first push to the formArray this throws an error in the console, that says:

ERROR Error: Cannot find control with name: 'partidaDetailLibre'

this is how I make the push to the form since component

    datosFacturaLibre = this.formBuilder.group({
    
        concepts: this.formBuilder.array([]),
    
      })
    
      get newPartidaLibre(): FormGroup {
    
        return this.formBuilder.group({
    
          claveSat: [''],
          claveUnidadSat: [''],
          unidad: [''],
          quantity: [''],
          description: [''],
          totalCostFinalAmount: [''],
          totalCostFinalAmountWithCurrency: [''],
          subtotal: [''],
          subtotalWithCurrency: [''],
          totalIva: [''],
          totalIvaWithCurrency: [''],
          total: [''],
          totalWithCurrency: [''],
    
        })
    
      }
    
      get partidaDetailLibre(): FormArray {
    
        return this.datosFacturaLibre.get('concepts') as FormArray;
    
      }
    
      async addPartidaLibre() {
    
        await this.partidaDetailLibre.push(this.newPartidaLibre);
    
      }

And in the HTML I got as this

    <form [formGroup]="datosFacturaLibre" autocomplete="off">
    
        <mat-card>
    
            <section style="padding: 10px" *ngIf="tipoFacturacion">
    
                <mat-horizontal-stepper [linear]="isLinear">
    
                    <mat-step label="Agregar conceptos">
                        <div formArrayName="partidaDetailLibre">
    
                            <div class="mat-elevation-z8" style="padding: 10px">
    
                                <table mat-table [dataSource]="partidaDetailLibre.controls">
    
                                    <!-- claveSat Column -->
                                    <ng-container matColumnDef="number">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center; padding-right: 15px; padding-left: 15px"> # </th>
                                        <td mat-cell *matCellDef="let row; index as i" [formGroup]="row"
                                            style="text-align: center; padding-right: 15px; padding-left: 15px">
                                            {{i+1}}
                                        </td>
                                    </ng-container>
    
                                    <!-- claveSat Column -->
                                    <ng-container matColumnDef="claveSat">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center"> Clave SAT
                                        </th>
                                        <td mat-cell *matCellDef="let row; index as i" style="text-align: center"
                                            [formGroup]="row">
    
                                            <input type="text" matInput
                                                (keyup)="getClaveSat($event.target.value); filterClaveSat($event.target.value)"
                                                formControlName="claveSat" [matAutocomplete]="autoClaveSat" style="border-bottom: 1px solid; width: 60px;"/>
                                            <mat-autocomplete #autoClaveSat [panelWidth]="300">
                                                <mat-option (click)="changeClaveSat(claveSat, i)"
                                                    (onSelectionChange)="changeClaveSat(claveSat, i)"
                                                    *ngFor="let claveSat of filteredClaveSat" [value]="claveSat">
                                                    {{claveSat.c_claveprodserv}} - {{claveSat.descripcion}}
                                                </mat-option>
                                            </mat-autocomplete>
    
                                        </td>
                                    </ng-container>
    
                                    <!-- claveUnSat Column -->
                                    <ng-container matColumnDef="claveUnSat">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center"> Clave de
                                            unidad
                                        </th>
    
                                        <td mat-cell *matCellDef="let row; index as i" style="text-align: center"
                                            [formGroup]="row">
    
    
                                            <input type="text" matInput
                                                (keyup)="getClaveUnidadSat($event.target.value); filterClaveUnidadSat($event.target.value)"
                                                formControlName="claveUnidadSat" [matAutocomplete]="autoClaveUnidadSat"  style="border-bottom: 1px solid; width: 60px;"/>
                                            <mat-autocomplete #autoClaveUnidadSat [panelWidth]="300">
                                                <mat-option (click)="changeClaveUnidadSat(claveUnidadSat, i)"
                                                    (onSelectionChange)="changeClaveUnidadSat(claveUnidadSat, i)"
                                                    *ngFor="let claveUnidadSat of filteredClaveUnidadSat"
                                                    [value]="claveUnidadSat">
                                                    {{claveUnidadSat.c_claveunidad}} - {{claveUnidadSat.nombre}}
                                                </mat-option>
                                            </mat-autocomplete>
    
                                        </td>
                                    </ng-container>
    
                                    <!-- unidad Column -->
                                    <ng-container matColumnDef="unidad">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center"> Unidad
                                        </th>
                                        <td mat-cell *matCellDef="let row" style="text-align: center" [formGroup]="row">
                                            <input matInput formControlName="unidad"
                                                style="height: 28px; text-align: center;" style="border-bottom: 1px solid; width: 60px;">
                                        </td>
                                    </ng-container>
    
                                    <!-- concepto Column -->
                                    <ng-container matColumnDef="concepto">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center"> Concepto
                                        </th>
                                        <td mat-cell *matCellDef="let row" style="text-align: center" [formGroup]="row">
                                            <input matInput formControlName="description"
                                                style="height: 28px; text-align: center;" style="border-bottom: 1px solid; width: 60px;">
                                        </td>
                                    </ng-container>
    
                                    <!-- cantidad Column -->
                                    <ng-container matColumnDef="cantidad">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center"> Cantidad
                                        </th>
                                        <td mat-cell *matCellDef="let row" style="text-align: center" [formGroup]="row">
                                            <input matInput formControlName="quantity"
                                                style="height: 28px; text-align: center;" style="border-bottom: 1px solid; width: 60px;">
                                        </td>
                                    </ng-container>
    
                                    <!-- precioUnitario Column -->
                                    <ng-container matColumnDef="precioUnitario">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center"> Precio
                                            Unitario
                                        </th>
                                        <td mat-cell *matCellDef="let row" style="text-align: center" [formGroup]="row">
                                            <input matInput formControlName="totalCostFinalAmountWithCurrency"
                                                style="height: 28px; text-align: center;" style="border-bottom: 1px solid; width: 60px;">
                                        </td>
                                    </ng-container>
    
                                    <!-- iva Column -->
                                    <ng-container matColumnDef="iva">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center"> IVA </th>
                                        <td mat-cell *matCellDef="let row" style="text-align: center" [formGroup]="row">
                                            <input matInput formControlName="totalIvaWithCurrency"
                                                style="height: 28px; text-align: center;" style="border-bottom: 1px solid; width: 60px;">
                                        </td>
                                    </ng-container>
    
                                    <!-- total Column -->
                                    <ng-container matColumnDef="total">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center"> Total
                                        </th>
                                        <td mat-cell *matCellDef="let row" style="text-align: center" [formGroup]="row">
                                            <input matInput formControlName="totalWithCurrency"
                                                style="height: 28px; text-align: center;" style="border-bottom: 1px solid; width: 60px;">
                                        </td>
                                    </ng-container>
    
                                    <!-- total Column -->
                                    <ng-container matColumnDef="acciones">
                                        <th mat-header-cell *matHeaderCellDef style="text-align: center"> Acciones
                                        </th>
                                        <td mat-cell *matCellDef="let row" style="text-align: center"> acciones
                                        </td>
                                    </ng-container>
    
                                    <tr mat-header-row *matHeaderRowDef="columnsConceptsLibre"></tr>
                                    <tr mat-row *matRowDef="let row; columns: columnsConceptsLibre;"></tr>
    
                                </table>
    
                                <div fxLayout="row" fxLayoutAlign="end center" style="margin-top: 16px">
    
                                    <table mat-table class="tbtotal" style="width: 40%;"
                                        [dataSource]="dataSourceConceptsTotals">
                                        <ng-container matColumnDef="concepto">
                                            <th mat-header-cell *matHeaderCellDef>Concepto</th>
                                            <td mat-cell *matCellDef="let element">
                                                {{element.concept}}</td>
                                        </ng-container>
    
                                        <ng-container matColumnDef="monto">
                                            <th mat-header-cell *matHeaderCellDef>Monto</th>
                                            <td mat-cell *matCellDef="let element">
                                                {{element.amount | currency}}</td>
                                        </ng-container>
    
                                        <ng-container matColumnDef="moneda">
                                            <th mat-header-cell *matHeaderCellDef>Moneda</th>
                                            <td mat-cell *matCellDef="let element">
                                                {{element.currency}}</td>
                                        </ng-container>
    
                                        <tr mat-header-row *matHeaderRowDef="columnsConceptsTotalsLibre; sticky: true">
                                        </tr>
                                        <tr mat-row *matRowDef="let row; columns: columnsConceptsTotalsLibre;"></tr>
                                    </table>
    
                                </div>
    
                            </div>
    
                        </div>
                    </mat-step>
                    <mat-step label="Timbrar">
                        <p>Segundo step</p>
                    </mat-step>
    
                </mat-horizontal-stepper>
    
            </section>
    
        </mat-card>
    
    </form>

I have a slide toggle to show or hide the form, when I make it appear, in the stackblitz example it does not take much time, but on my pc it does

stackblitz Example

hope someone can help me to know how I can reduce the time taken to show the form and get rid of the console error

1 Answer

The console error:

Error: Cannot find control with name: 'partidaDetailLibre'

It means that you haven't defined a FormArray with this name. In your code I can see:

datosFacturaLibre = this.formBuilder.group({
    concepts: this.formBuilder.array([]),
  });

and

 get partidaDetailLibre(): FormArray {
        return this.datosFacturaLibre.get('concepts') as FormArray;
    }

Change concepts with partidaDetailLibre. It solves the error.

On the other hand, why are you checking twice tipoFacturacion?

<form
  [formGroup]="datosFacturaLibre"
  autocomplete="off"
  *ngIf="tipoFacturacion"
>
  <mat-card>
    <section style="padding: 10px" *ngIf="tipoFacturacion">
      <mat-horizontal-stepper [linear]="isLinear">
        <mat-step label="Agregar conceptos">
          <div formArrayName="partidaDetailLibre">
......

It's not neccessary. Remove the second one.

If you want to show and hide the form, change the method of the in this way:

cambioTipoFacturacion() {
        this.tipoFacturacion = !this.tipoFacturacion;
}

Here the Stackblitz with your code and the changes:

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

James H. Sterling
Author

James H. Sterling

James Sterling reports on renewable energy developments, climate policy, ecological conservation, and green tech innovations around the globe.