首页 > 解决方案 > 带有反应形式的 Angular Mat-Table 在单击按钮时不显示数据,它会添加带有错误的空行

问题描述

AddRow_click()上,我正在填充insuranceFormArray并将其值分配给datasource。但是在添加之后,我在表中添加了一个空行,我在控制台中也收到了以下错误消息。我只显示了其中一些错误,因为它们在我的 html 上的所有表单控件中重复出现。

保险组件.ts

import { Component, OnInit, Inject, ChangeDetectorRef, ɵConsole } from '@angular/core';
import { MatDialogRef, MatTableDataSource, MatPaginator, MAT_DIALOG_DATA, MatTable, MatSort } from '@angular/material';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { AssetEntity } from 'src/app/model/proposal/asset-entity.moodel';
import { ProposalAssetInsurance } from 'src/app/model/proposal/proposal-asset-insurance.model';
import { userInfo } from 'os';
import { AppStorage } from 'src/app/core/appstorage';
import { SessionKeys } from 'src/app/core/SessionKeys';
import { ProposalEntity } from 'src/app/model/proposal/proposal-entity.model';
import { validateConfig } from '@angular/router/src/config';
import { forkJoin } from 'rxjs/internal/observable/forkJoin';
import { LookupService } from 'src/app/services/data-services/lookup.service';
import { FormControl, FormGroup, Validators, FormBuilder, FormArray } from '@angular/forms';
import { _MatTabHeaderMixinBase } from '@angular/material/tabs/typings/tab-header';
import { CurrencyIndex } from '@angular/common/src/i18n/locale_data';

@Component({
  selector: 'app-insurance',
  templateUrl: './insurance.component.html',
  animations: [
    trigger('detailExpand', [
      state('collapsed', style({ height: '0px', minHeight: '0' })),
      state('expanded', style({ height: '*' })),
      transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
    ]),
  ],
  styleUrls: ['./insurance.component.css']
})
export class InsuranceComponent  implements OnInit{
  displayedColumns = [ 'insuranceCategoryCode',
  'insuranceCoverageTypeCode',
  'insuranceTypeCode',
  'insurer',
  'policyNumber',
  'insuredPerson',
  'duration',
  'currencyCode',
  'insuredAmount',
  'startDate',
  'expiryDate',
  'premiumAmount',
  'commissionPct',
  'componentFinanceTypeCode',
  'marginRate',
  'Delete'
];
  
   assetIndex:number=0;
   insurances : ProposalAssetInsurance[];
   proposalEntity : ProposalEntity;
   user = this.appStorage.getFromSession(SessionKeys[SessionKeys.USER]);
   selectedIndex : number ;
    InsuranceControl = new FormControl();
    InsuranceCategories = [];
    InsuranceCoverageTypes = [];
    InsuranceTypes = [];
    Insurers = [];
    Currencies = [];
    FinanceTypes =[];
    insuranceFormGroup:FormGroup;
    insuranceFormArray:FormArray;
  dataSource = new MatTableDataSource<ProposalAssetInsurance>();
  constructor(  private fb: FormBuilder,
      private cd: ChangeDetectorRef,
    private appStorage: AppStorage,
    private lookupService: LookupService,
    private matRefDialog:MatDialogRef<InsuranceComponent>,@Inject(MAT_DIALOG_DATA) public data: any) { }
  ngOnInit(){
    this.insuranceFormArray = this.fb.array([]);
    this.insuranceFormGroup = this.fb.group({
      insuranceFormArray: [this.insuranceFormArray]
    });
    this.insurances = this.data.proposalEntity.ProposalArticleEntity[this.assetIndex].AssetEntity.ProposalAssetInsurances;
    this.proposalEntity = this.data.proposalEntity;

    var res = forkJoin(
      {
        InsuranceCategories: this.lookupService.GetInsuranceCategories(),
        InsuranceCoverageTypes: this.lookupService.GetInsuranceCoverageTypes(),
        InsuranceTypes: this.lookupService.GetInsuranceTypes(this.proposalEntity.Proposal.financialProductId),
        Insurers: this.lookupService.GetInsuranceCompanies(),
        Currencies : this.lookupService.GetCurrencies(),
        FinanceTypes : this.lookupService.GetComponentFinanceTypes(),
      }
    );
    res.subscribe(p => {
      this.InsuranceCategories = p.InsuranceCategories.Payload;
      this.InsuranceCoverageTypes = p.InsuranceCoverageTypes.Payload;
      this.InsuranceTypes = p.InsuranceTypes.Payload;
      this.Insurers = p.Insurers.Payload;
      this.Currencies = p.Currencies.Payload;
      this.FinanceTypes = p.FinanceTypes.Payload;
    }
    );
    if(this.insurances) 
    {
      for(let ins of this.insurances)
      {
        this.insuranceFormArray.push(this.initiateForm(ins));
      }
    }
    this.dataSource.data = this.insuranceFormArray.value;
    console.log("OnInit:"+this.insuranceFormArray.value);
  }
  initiateForm(ins:ProposalAssetInsurance): FormGroup {
    return this.fb.group({
      insuranceCategoryCode: [ins.insuranceCategoryCode , Validators.required],
      insuranceCoverageTypeCode: [ins.insuranceCoverageTypeCode, Validators.required],
      insuranceTypeCode: [ins.insuranceTypeCode, Validators.required],

      insurer:[ins.insurer, Validators.required],
      policyNumber: [ins.policyNumber, Validators.required],
      insuredPerson: [ins.insuredPerson, Validators.required],

      duration: [ins.duration, Validators.required],
      currencyCode: [ins.currencyCode, Validators.required],
      insuredAmount: [ins.insuredAmount, Validators.required],

      startDate:[ins.startDate, Validators.required],
      expiryDate: [ins.expiryDate, Validators.required],
      premiumAmount: [ins.premiumAmount, Validators.required],

      commissionPct:[ins.commissionPct, Validators.required],
      componentFinanceTypeCode: [ins.componentFinanceTypeCode],
      marginRate: [ins.marginRate, Validators.required]
    });
  }
  DeleteRow_click(index:any)
  {
    this.insuranceFormArray.removeAt(index);
    console.log("OnDelete:"+this.insuranceFormArray.value);
    this.dataSource.data = this.insuranceFormArray.value;
    this.cd.detectChanges();
  }
  AddRow_click(item: any)
{
    if(!this.validate())
  {
    return;
  }
   var proposalAssetInsurance = new ProposalAssetInsurance();
  proposalAssetInsurance.processingDate = this.user.processingDate;//new Date(this.user.processingDate);
  proposalAssetInsurance.currencyCode = this.proposalEntity.Proposal.currencyCode;
  proposalAssetInsurance.proposalId = this.proposalEntity.Proposal.proposalId;
  proposalAssetInsurance.insuredAmount = this.proposalEntity.ProposalArticleEntity[this.assetIndex].AssetEntity.ProposalFinancialAgreement.assetAmount;
  proposalAssetInsurance.duration = this.proposalEntity.ProposalArticleEntity[this.assetIndex].AssetEntity.ProposalFinancialAgreement.contractTerms;
  proposalAssetInsurance.startDate = this.proposalEntity.ProposalArticleEntity[this.assetIndex].AssetEntity.ProposalFinancialAgreement.contractStartDate;
  proposalAssetInsurance.marginRateInd = false;
  proposalAssetInsurance.financeOptionEnableInd = true;

                
if (proposalAssetInsurance.startDate != null)
{
  var expiry = this.proposalEntity.ProposalArticleEntity[this.assetIndex].AssetEntity.ProposalFinancialAgreement.contractStartDate;
  // var years =proposalAssetInsurance.duration/12;
  expiry.setFullYear(expiry.getFullYear() + 1);
  expiry.setDate(expiry.getDate() - 1);
  proposalAssetInsurance.expiryDate = expiry;
}
this.insuranceFormArray.push(this.initiateForm(proposalAssetInsurance));

console.log("OnAdd:"+this.insuranceFormArray.value);
this.dataSource.data = this.insuranceFormArray.value;
this.cd.detectChanges();
  }
  closeDialog()
{
  this.matRefDialog.close();
}
openDetail(index:number)
{
  //this.data.proposalEntity.ProposalArticleEntity[this.assetIndex].AssetEntity.ProposalRepaymentPlanEntity
}
validate():boolean
{
  return true;
}
}

保险.component.html

<div class="dialog-header sticking-top-main" >
  <h3><strong style="color: white !important;">Insurance</strong></h3>
  <button mat-icon-button class="close-button" [mat-dialog-close]="true">
    <mat-icon class="close-icon" [ngStyle]="{'color':'white'}">close</mat-icon>
  </button>
</div>
<div class="row" style="width: 95%;margin-left: 40px;">
      <button mat-icon-button matTooltip="Add row" (click)="AddRow_click($event)">
          <i class="fa fa-plus fa-2x" style="color: var(--theme-color);"></i>
      </button>
      &nbsp;
      <button mat-icon-button matTooltip="Calculate" (click)="calculate_click($event)">
          <i class="fa fa-calculator fa-2x" style="color: var(--theme-color);"></i>
      </button>
  </div>
<div [formGroup]="insuranceFormGroup"  class="example-container mat-elevation-z8 scrollbar scrollbar-primary" style="height: 75%; width: 95%;">
  <!-- table table-bordered  -->
  <mat-table #table [dataSource]="dataSource" style="width: fit-content;" formArrayName="insuranceFormArray">
    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row;let i = index; columns: displayedColumns;" [formGroupName]="i"></mat-row>
    <!-- insuranceCategoryCode Column -->
    <ng-container matColumnDef="insuranceCategoryCode">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Insurance Category</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element; let i=index" >
        <mat-select formControlName="insuranceCategoryCode">
          <mat-option [value]="item.CODE" *ngFor="let item of InsuranceCategories">
            {{ item.DESCRIPTION }}
          </mat-option>
        </mat-select>
      </mat-cell>
    </ng-container>

    <!-- insuranceCoverageTypeCode Column -->
    <ng-container matColumnDef="insuranceCoverageTypeCode">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Insurance Coverage</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element">
        <mat-select formControlName="insuranceCoverageTypeCode">
          <mat-option [value]="item.CODE" *ngFor="let item of InsuranceCoverageTypes">
            {{ item.DESCRIPTION }}
          </mat-option>
        </mat-select>
      </mat-cell>
    </ng-container>

    <!-- insuranceTypeCode Column -->
    <ng-container matColumnDef="insuranceTypeCode">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Insurance Type</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element">
        <mat-select formControlName="insuranceTypeCode">
          <mat-option [value]="item.CODE" *ngFor="let item of InsuranceTypes">
            {{ item.DESCRIPTION }}
          </mat-option>
        </mat-select>
      </mat-cell>
    </ng-container>

    <!-- insurer Column -->
    <ng-container matColumnDef="insurer">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Insurer</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element">
        <mat-select formControlName="insurer">
          <mat-option [value]="item.CODE" *ngFor="let item of Insurers">
            {{ item.DESCRIPTION }}
          </mat-option>
        </mat-select>
      </mat-cell>
    </ng-container>

    <!-- policyNumber Column -->
    <ng-container matColumnDef="policyNumber">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Policy Number</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element"> 
        <input matInput name="txtpolicyNumber" formControlName="policyNumber" > </mat-cell>
    </ng-container>

    <!-- insuredPerson Column -->
    <ng-container matColumnDef="insuredPerson">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Insured Person</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element"> 
        <input matInput name="insuredPerson" formControlName="insuredPerson" > </mat-cell>
    </ng-container>

    <!-- duration Column -->
    <ng-container matColumnDef="duration">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Duration</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element"> 
        <input matInput name="duration" formControlName="duration" > </mat-cell>
    </ng-container>

    <!-- currencyCode Column -->
    <ng-container matColumnDef="currencyCode">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Currency</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element">
        <mat-select formControlName="currencyCode">
          <mat-option [value]="item.CODE" *ngFor="let item of Currencies">
            {{ item.DESCRIPTION }}
          </mat-option>
        </mat-select>
      </mat-cell>
    </ng-container>

    <!-- insuredAmount Column -->
    <ng-container matColumnDef="insuredAmount">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Insured Amount</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element"> 
        <input matInput name="insuredAmount" formControlName="insuredAmount" > </mat-cell>
    </ng-container>

    <!-- startDate Column -->
    <ng-container matColumnDef="startDate">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Start Date</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element"> 
          <input name="dtpStartDate" matInput
                [matDatepicker]="StartDatePicker" formControlName="startDate"
                (focus)="StartDatePicker.open()" >
          <mat-datepicker #StartDatePicker></mat-datepicker>
          </mat-cell>
    </ng-container>

    <!-- expiryDate Column -->
    <ng-container matColumnDef="expiryDate">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Expiry Date</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element"> 
          <input name="dtpexpiryDate" matInput
                [matDatepicker]="expiryDatePicker" formControlName="expiryDate"
                (focus)="expiryDatePicker.open()" >
          <mat-datepicker #expiryDatePicker></mat-datepicker>
          </mat-cell>
    </ng-container>

  <!-- premiumAmount Column -->
  <ng-container matColumnDef="premiumAmount">
    <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
      <div style="width: 100%;">Premium Amount</div> 
    </mat-header-cell>
    <mat-cell class="text-centre" *matCellDef="let element"> 
      <input matInput name="premiumAmount" formControlName="premiumAmount" > </mat-cell>
  </ng-container>

  <!-- commissionPct Column -->
  <ng-container matColumnDef="commissionPct">
    <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
      <div style="width: 100%;">Commission %</div> 
    </mat-header-cell>
    <mat-cell class="text-centre" *matCellDef="let element"> 
      <input matInput name="commissionPct" formControlName="commissionPct" > </mat-cell>
  </ng-container>

  <!-- componentFinanceTypeCode Column -->
  <ng-container matColumnDef="componentFinanceTypeCode">
    <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
      <div style="width: 100%;">Financed</div> 
    </mat-header-cell>
    <mat-cell class="text-centre" *matCellDef="let element">
      <mat-select formControlName="componentFinanceTypeCode">
        <mat-option [value]="item.CODE" *ngFor="let item of FinanceTypes">
          {{ item.DESCRIPTION }}
        </mat-option>
      </mat-select>
    </mat-cell>
  </ng-container>

  <!-- marginRate Column -->
  <ng-container matColumnDef="marginRate">
    <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
      <div style="width: 100%;">Customer Rate</div> 
    </mat-header-cell>
    <mat-cell class="text-centre" *matCellDef="let element"> 
      <input matInput name="marginRate" formControlName="marginRate" > </mat-cell>
  </ng-container>

  <!-- Delete Column -->
  <ng-container matColumnDef="Delete">
    <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
      <div style="width: 100%;"></div> 
    </mat-header-cell>
    <mat-cell class="text-centre" *matCellDef="let element;let i = index;"> 
      <button mat-icon-button matTooltip="Delete" (click)="DeleteRow_click(i)">
        <i class="fa fa-trash" style="color: var(--theme-color);"></i>
    </button>
  </mat-cell>
  </ng-container>

    
  </mat-table>
    </div>
    <div class="row" style="width: 95%;margin-left: 40px; font-size: 1.5vw;font-weight: bold;">
      <label style="color: var(--theme-color);">Total Amount:</label>&nbsp;
      <label style="text-decoration: underline;color: var(--theme-color);"> € 0.00 </label>
  </div>

错误

InsuranceComponent.html:20 ERROR Error: Cannot find control with path: 'insuranceFormArray -> 0'
        at _throwError (forms.js:2436)
        at setUpFormContainer (forms.js:2408)
        at FormGroupDirective.addFormGroup (forms.js:5806)
        at FormGroupName.ngOnInit (forms.js:2590)
        at checkAndUpdateDirectiveInline (core.js:24503)
        at checkAndUpdateNodeInline (core.js:35163)
        at checkAndUpdateNode (core.js:35102)
        at debugCheckAndUpdateNode (core.js:36124)
        at debugCheckDirectivesFn (core.js:36067)
        at Object.eval [as updateDirectives] (InsuranceComponent.html:20)
    View_InsuranceComponent_2 @ InsuranceComponent.html:19
    InsuranceComponent.html:20 ERROR CONTEXT DebugContext_
    View_InsuranceComponent_2 @ InsuranceComponent.html:19
    InsuranceComponent.html:27 ERROR Error: Cannot find control with path: 'insuranceFormArray -> insuranceCategoryCode'
        at _throwError (forms.js:2436)
        at setUpControl (forms.js:2304)
        at FormGroupDirective.addControl (forms.js:5776)
        at FormControlName._setUpControl (forms.js:6408)
        at FormControlName.ngOnChanges (forms.js:6331)
        at checkAndUpdateDirectiveInline (core.js:24499)
        at checkAndUpdateNodeInline (core.js:35163)
        at checkAndUpdateNode (core.js:35102)
        at debugCheckAndUpdateNode (core.js:36124)
        at debugCheckDirectivesFn (core.js:36067)
    View_InsuranceComponent_4 @ InsuranceComponent.html:26
    InsuranceComponent.html:27 ERROR CONTEXT DebugContext_
    View_InsuranceComponent_4 @ InsuranceComponent.html:26
    InsuranceComponent.html:41 ERROR Error: Cannot find control with path: 'insuranceFormArray -> insuranceCoverageTypeCode'

标签: angulartypescriptangular-materialangular-reactive-formsmat-table

解决方案


使用以下帮助解决了我的问题。堆栈闪电战。我刚刚在我的matCellDef中给出了FormGroup的相对索引,就像这样。希望它可以帮助寻找答案的人。

<ng-container matColumnDef="insuranceCategoryCode">
      <mat-header-cell *matHeaderCellDef class="text-centre strong-700 sticking-top"> 
        <div style="width: 100%;">Insurance Category</div> 
      </mat-header-cell>
      <mat-cell class="text-centre" *matCellDef="let element; let i=index" [formGroup]="insuranceFormArray.at(i)" >
        <mat-select name="insuranceCategoryCode" formControlName="insuranceCategoryCode">
          <mat-option [value]="item.CODE" *ngFor="let item of InsuranceCategories">
            {{ item.DESCRIPTION }}
          </mat-option>
        </mat-select>
      </mat-cell>
    </ng-container>

推荐阅读