You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular13+中AbstractControl不存在controls属性的修复方案咨询

Angular 13+ 响应式表单 Property 'controls' does not exist on type 'AbstractControl<any, any>' 修复方案

问题根源

Angular 13+ 强化了表单控件的类型检查,AbstractControl 基类并不包含 controls 属性,只有 FormGroup 和 FormArray 子类才有该属性。之前的代码直接通过 AbstractControl 实例访问 controls,在严格类型检查下会触发报错。

TypeScript代码修复

修改两处核心逻辑,避免直接访问 controls 属性,改用类型断言或 get() 方法:

  1. sumOfOwed 方法:遍历 FormArray 时,将每个 AbstractControl 断言为 FormGroup,同时添加空值保护避免报错:
sumOfOwed() {
  this.items = this.form.get('items') as FormArray;
  this.sum = 0;
  this.items.controls.forEach((control) => {
    const itemGroup = control as FormGroup;
    this.sum += itemGroup.get('owedInDollars')?.value || 0;
    this.totalsum = this.sum;
  });
  console.log(`Total Owed in Dollars: ${this.sum}`);
}
  1. selectOption 方法:用 get() 方法替代直接访问 item.controls,遍历控件时添加类型断言:
selectOption(item: FormGroup, option: string) {
  item.get('dispute')?.setValue(option === 'dispute' ? 'dispute' : '');
  item.get('return')?.setValue(option === 'return' ? 'return' : '');
  item.get('takePayment')?.setValue(option === 'takePayment' ? 'takePayment' : '');

  let total = 0;
  this.items.controls.forEach((control) => {
    const itemGroup = control as FormGroup;
    const owed = itemGroup.get('owedInDollars')?.value || 0;
    const disputeVal = itemGroup.get('dispute')?.value;
    const returnVal = itemGroup.get('return')?.value;
    if (disputeVal || returnVal) {
      total += owed;
    }
  });
  console.log(`New Total Owed in Dollars: ${this.sum - total}`);
  this.totalsum = this.sum - total;
}

HTML模板修复

模板中直接访问 item.controls 会触发类型错误,改用 get() 方法访问控件值,同时调用方法时添加类型断言:

<form [formGroup]="form">
<table id="customers">
  <thead>
    <tr>
      <th>Device Name</th>
      <th>Model Number</th>
      <th>Serial Number</th>
      <th>Dispute</th>
      <th>Return</th>
      <th>Take Payment</th>
      <th>Owed in Dollars</th>
    </tr>
  </thead>
  <tbody formArrayName="items">
    <tr *ngFor="let item of items.controls; let i=index" [formGroupName]="i">
      <td>{{ item.get('deviceName')?.value }}</td>
      <td>{{ item.get('modelNumber')?.value }}</td>
      <td>{{ item.get('serialNumber')?.value }}</td>
      <td><input type="radio" formControlName="dispute" value="dispute" (click)="selectOption(item as FormGroup, 'dispute')"></td>
      <td><input type="radio" formControlName="return" value="return" (click)="selectOption(item as FormGroup, 'return')"></td>
      <td><input type="radio" formControlName="takePayment" value="takePayment" (click)="selectOption(item as FormGroup, 'takePayment')" [checked]="true"></td>
      <td>{{ item.get('owedInDollars')?.value }}</td>
    </tr>
    <tr *ngFor="let item of items.controls; let i=index" [formGroupName]="i">
      <td colspan="7" *ngIf="item.get('dispute')?.value">
        <label>Reason:</label>
        <select formControlName="reason">
          <option value="">--Select--</option>
          <option value="Damaged">Damaged</option>
          <option value="Wrong Item">Wrong Item</option>
          <option value="Missing Part">Missing Part</option>
          <option value="Other">Other</option>
        </select>
      </td>
    </tr>
  </tbody>
</table>
</form>
<div><h2>{{totalsum}}</h2></div>

额外优化建议

可以在组件中添加一个 getter 方法,简化 FormArray 的类型转换:

get itemsArray(): FormArray {
  return this.form.get('items') as FormArray;
}

之后模板和TS代码中都可以用 this.itemsArray 替代 this.items,减少重复的类型断言逻辑。

内容的提问来源于stack exchange,提问作者Teja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 10:04:53