2

我正在处理具有嵌套 Formarray 的页面。

constructor(private fb: FormBuilder) {
      this.buildForm();
  }

  private buildForm() {
    this.trialBudgetForm = this.fb.group({
        clients: this.fb.array([])
    })
  }
  addCustomer() {
    this.clients.push(this.initCustomer());
  }
  initCustomer() {
    return this.fb.group({
      earnedIncomes: this.fb.array([this.initIncome()]),
      thirtyAndOneThirdYN: [],
      thirtyYN: [],
      earnedIncomeExpenseType: [],
      earnedIncomeExpense: [],
      dependentCareExpense: []
    })
  }
  initIncome() {
     return this.fb.group(new ScrAmountType());
  }
   ngOnInit() {
      this.populateData();
   }
  populateData() {
     const clients = this.TrialBudgetData.clients;
     const customerFGs = clients.map(customer => this.fb.group({
     earnedIncomes: this.populateIncome(customer.earnedIncomes),
     thirtyAndOneThirdYN: [this.utilService.YNConvert(customer.thirtyAndOneThirdYN)],
     thirtyYN: [this.utilService.YNConvert(customer.thirtyYN)],
     earnedIncomeExpenseType: [customer.earnedIncomeExpenseType],
     earnedIncomeExpense: [customer.earnedIncomeExpense],
     dependentCareExpense: [customer.dependentCareExpense]
     }));
     const customerFormArray = this.fb.array(customerFGs);
     this.trialBudgetForm.setControl('clients', customerFormArray);
}

出于演示目的,我没有发布整个 ts 文件,因为有将近 600 行。但如果需要,我可以提供更多细节。这是html页面(也只是一个片段)

<form novalidate [formGroup]="trialBudgetForm" (ngSubmit)="save(trialBudgetForm)">
<div class="settingsPage-box">
      <h3 class="box-border-bottom">Earned Income
        <span class="float_right add-field add-margin hand" (click)="addCustomer()">
          <i class=" fa fa-plus-circle fa-lg plusIconColor"></i>
          <span>
            &nbsp;&nbsp;Add Earned Income
          </span>
        </span>
      </h3>
      <div formArrayName="clients">
        <div *ngFor="let earnedIncomeCustomer of clients.controls; let i = index" [formGroupName]="i" class="row-view box-border-bottom">
          <div class="box-border-bottom row-view">
            <div class="col-sm-3 padding0">
              <label for="customer{{i+1}}" class="pushDown">Customer {{i+1}}:</label>
            </div>
            <div class="col-sm-9 grid-block padding0">
              <div class="col-sm-1 float_right" (click)="deleteCustomer(i)">
                <span class="delete-row hand">
                    <i class="fa fa-trash-o"></i>
                  </span>
              </div>
            </div>
            <div class="col-sm-3">
              <label class="pushDown">Earned Income</label>
            </div>
            <div class="col-sm-9 grid-block">
              <div class="row">
                <div class="col-sm-6 u-justifyEnd">
                  <span class="add-margin float-left hand" (click)="addEarnedIncome(i)"><i class=" fa fa-plus-circle fa-lg plusIconColor"></i><span>&nbsp;&nbsp;Add Income</span></span>
                </div>
              </div>
              <div class="row grid-block pd-left amount-grid" formArrayName="earnedIncomes" >
                <div class="row-view" *ngFor="let earnedIncome of earnedIncomeCustomer.controls.earnedIncomes.controls; let j = index"
                  [formGroupName]="j">
                  <div class="col-sm-5 padding5">
                    <span class="label-type" *ngIf="j==0">Type</span>
                    <select class="form-control" formControlName="type" (change)="checkForDuplicateEarnedIncomeType(this.trialBudgetForm.controls.clients.controls[i].controls.earnedIncomes.controls[j].value.type)">
                      <option value="">Select</option>
                      <option *ngFor="let optionEntity of this.constantsService.getDropDownFromLookup(this.constantsService.getText('EarningType'))"
                        value="{{optionEntity.lookupBean.code}}">{{optionEntity.lookupBean.longLabel}}</option>
                    </select>
                  </div>
                  <div class="col-sm-6 pd-left padding5 amount-bg">
                    <span class="label-type" *ngIf="j==0">Amount</span>
                    <div class="search-container">
                      <input (keypress)="this.customValidatorsService.validateNumberOnly($event)" formControlName="amount" class="form-control amount-input search-box"
                        placeholder="$0.00" currencyMask [options]="{ allowNegative: false,prefix: '$',hundreds: ',' }" maxlength="12"
                        (keyup)="calculateTotalIncome(earnedIncomeCustomer, i)" />
                    </div>
                    <div class="clearfix"></div>
                  </div>
                  <div class="col-sm-1 pd-left">
                    <span class="label-type" *ngIf="j==0">&nbsp;</span>
                    <span class="delete-row hand" (click)="deleteIncome(earnedIncomeCustomer, i, j)"> <!-- G.S Income.controls.amount -->
                        <i class="fa fa-trash-o"></i>
                      </span>
                  </div>
                </div>
                <div class="row-view">
                  <div class="col-sm-5">
                    <span class="total-info text-right">Total Earned Income</span>
                  </div>
                  <div class="col-sm-6 pd-left amount-bg">
                    <span class="total-info text-right">${{ earnedIncomeCustomer.totalEarnedIncome | number : '1.2-2'}} 
                    </span>
                    <div class="clearfix"></div>
                  </div>
                </div>
                <div class="row-view">
                  <div class="col-sm-12 text-center">
                    <div class="clearfix"></div>
                  </div>
                </div>
              </div>
              <span *ngIf="duplicateEarnedIncomeType" class="red-font-color">Choose a different use type</span>
            </div>
            <div class="clearfix"></div>
          </div>

          <div class="box-border-bottom row-view">
            <div class="col-sm-3">
              <label class="pushDown">Earned Income Options</label>
            </div>
            <div class="col-sm-8 grid-block">
              <div class="col-sm-5 form-group label-check display-check">
                <input type="checkbox" id="check-1" formControlName="thirtyAndOneThirdYN">
                <label for="check-1">30+1/3</label>
              </div>
              <div class="col-sm-6 form-group label-check display-check">
                <input type="checkbox" id="check-2"  formControlName="thirtyYN">
                <label for="check-2">$30</label>
              </div>
            </div>
            <div class="clearfix"></div>
          </div>
          <div class="box-border-bottom row-view">
            <div class="col-sm-3">
              <label class="pushDown">Earned Income Expenses</label>
            </div>
            <div class="col-sm-8 grid-block">
              <div class="col-sm-5 form-group padding_right">
                <div class="control-label">Type</div>
                <select class="form-control" formControlName="earnedIncomeExpenseType">
                  <option value="-1">Select</option>
                    <option *ngFor="let optionEntity of this.constantsService.getDropDownFromLookup(this.constantsService.getText('EIexpenseType'))"
                        value="{{optionEntity.lookupBean.code}}">{{optionEntity.lookupBean.longLabel}}</option>
                </select>
              </div>
              <div class="col-sm-6 padding0 padding_custom">
                <div class="control-label">Amount</div>
                <input formControlName="earnedIncomeExpense" currencyMask (keypress)="numberOnly($event)" class="form-control" [options]="{ allowNegative: false, prefix: '$',hundreds: ',' }"
                  placeholder="$0.00" maxlength="10" />
              </div>
            </div>
            <div class="clearfix"></div>
          </div>

          <div class="row-view">
            <div class="col-sm-3">
              <label class="pushDown">Dependent Care Expenses</label>
            </div>
            <div class="col-sm-8 grid-block">
              <div class="col-sm-5">
                <div class="control-label">Expenses</div>
                <input (keypress)="numberOnly($event)" currencyMask formControlName="dependentCareExpense" class="form-control" maxlength="10"
                  placeholder="$0.00" [options]="{ allowNegative: false, prefix: '$',hundreds: ',' }" />
              </div>
            </div>
            <div class="clearfix"></div>
          </div>
        </div>
      </div>
    </div>
  </form>

我已经尝试调试了几天了。该问题发生在构造函数执行之后和调用 ngOnInit 之前。仅当我添加多个客户并返回此页面时才会出现此错误。(添加客户不会导致任何问题,只有当我回到此页面时this.validator is not a function才会显示错误。

这很奇怪,因为错误发生在构造函数和ngOnInit之间,并且在ngOnInit中调用了populateData,这意味着在页面知道我将加载多少客户之前发生错误。但是,如果由于我添加了多个客户而仅发生错误,则似乎应用程序必须在构造函数中获取该信息,而我尚未在其中加载数据。

更新 1:美国东部标准时间 9 月 25 日下午 3:39 更新了 populateData 函数

更新 2:全栈错误:美国东部标准时间 9 月 25 日下午 4:09

TrialBudgetComponent_Host.html:1 ERROR TypeError: this.validator is not a function
at FormControl.webpackJsonp.../../../forms/@angular/forms.es5.js.AbstractControl._runValidator (forms.es5.js:2645)
at FormControl.webpackJsonp.../../../forms/@angular/forms.es5.js.AbstractControl.updateValueAndValidity (forms.es5.js:2613)
at new FormControl (forms.es5.js:2936)
at FormBuilder.webpackJsonp.../../../forms/@angular/forms.es5.js.FormBuilder.control (forms.es5.js:5780)
at FormBuilder.webpackJsonp.../../../forms/@angular/forms.es5.js.FormBuilder._createControl (forms.es5.js:5822)
at forms.es5.js:5804
at Array.forEach (<anonymous>)
at FormBuilder.webpackJsonp.../../../forms/@angular/forms.es5.js.FormBuilder._reduceControls (forms.es5.js:5803)
at FormBuilder.webpackJsonp.../../../forms/@angular/forms.es5.js.FormBuilder.group (forms.es5.js:5762)
at TrialBudgetComponent.webpackJsonp.../../../../../src/app/trial-budget/trial-budget.component.ts.TrialBudgetComponent.toFromGroup (trial-budget.component.ts:102)

更新 3 问题已关闭:感谢 @yurzui 的评论,我才意识到此页面的架构搞砸了。该组件有一个父组件,其模板中只有(当前组件选择器)。这两个组件在不同的文件夹下具有完全相同的名称。父级位于 /trial-budget,子级位于 /trial-budget/trial-budget-main。TrialBudgetComponent.toFromGroup 实际上是父级内部的一个函数。出于某种原因,它在 ngInit 而不是构造函数中被调用。仍然没有弄清楚为什么错误只发生在 2 个客户身上。但吸取的教训:1. 仔细阅读错误信息,尤其是第一行和最后几行。我没有看最后一行。2. 始终在构造函数中构造表单并在 ngOnInit() 中填充数据

4

0 回答 0