Angular8升级到12后报错:Property 'controls' does not exist on type 'AbstractControl'
报错原因
Angular 12及以上版本收紧了响应式表单的类型校验规则,你遇到的报错本质是类型不匹配:
- FormArray的
controls属性返回的数组元素类型为AbstractControl AbstractControl是FormControl、FormGroup、FormArray的公共父类,本身没有controls属性,只有FormGroup子类才有该属性- Angular 8版本对该场景的类型检查宽松,所以代码可以正常运行,升级后强类型检查触发了报错
解决方案
以下三种方案均可解决问题,按推荐度排序:
方案1:自定义类型转换管道(最推荐,保留类型校验能力)
第一步:新增一个纯管道用于类型转换,代码如下:
// to-form-group.pipe.ts import { Pipe, PipeTransform } from '@angular/core'; import { AbstractControl, FormGroup } from '@angular/forms'; @Pipe({ name: 'toFormGroup' }) export class ToFormGroupPipe implements PipeTransform { transform(control: AbstractControl): FormGroup { return control as FormGroup; } }
第二步:将该管道添加到对应模块的declarations数组中。
第三步:模板内使用管道转换类型,修改后的代码示例:
<div *ngFor="let ticket of t.controls; let i = index"> <div [formGroup]="ticket | toFormGroup" class="form-row"> <div class="input-group col-md-12" style="padding: .15em .5em"> <div class="input-group-prepend col-md-10" style="padding: 0; margin: 0;"> <label class="input-group-text w-15">{{i + 1}}</label> <label class="input-group-text w-100" style="text-align: left; white-space: normal;"> {{(ticket | toFormGroup).controls.name.value}} </label> </div> <select formControlName="controlName" class="form-control col-md-2" style="height:auto !important;" [ngClass]="{ 'is-invalid': submitted && (ticket | toFormGroup).controls.controlName.errors }" (change)="onChange($event.target.value, i)"> <option [ngValue]="null"> --Select-- </option> <option *ngFor="let ansItem of formdetail.questionList[i].answerList" [ngValue]="ansItem" >{{ansItem.anstext}}</option> </select> <div *ngIf="submitted && (ticket | toFormGroup).controls.controlName.errors" class="invalid-feedback" style="height:auto !important;" [ngClass]="{ 'input-group-append': submitted && (ticket | toFormGroup).controls.controlName.errors, 'col-md-1': submitted && (ticket | toFormGroup).controls.controlName.errors }"> <div *ngIf="(ticket | toFormGroup).controls.controlName.errors.required">Required</div> </div> </div> </div> </div>
方案2:组件内新增类型转换方法
在组件ts文件中新增转换方法:
getAsFormGroup(control: AbstractControl): FormGroup { return control as FormGroup; }
模板内调用该方法即可,使用逻辑和方案1的管道一致,将ticket | toFormGroup替换为getAsFormGroup(ticket)即可。
方案3:使用$any()绕过类型检查(最快,不推荐长期使用)
Angular模板内置的$any()方法可以临时关闭变量的类型检查,修改写法如下:
{{$any(ticket).controls.name.value}} [ngClass]="{ 'is-invalid': submitted && $any(ticket).controls.controlName.errors }"
补充说明
你之前尝试的ticket.get('controlName')写法本身是正确的,未生效大概率是没有加可选链运算符?.,正确写法为:
[ngClass]="{ 'is-invalid': submitted && ticket.get('controlName')?.errors }"
另外注意你提供的模板代码里有一个笔误:</div>写成了/div>,需要修正避免编译报错。
内容的提问来源于stack exchange,提问作者DotNetBeginner
相关产品推荐
相关产品推荐

