Angular Reactive Forms报Cannot find control with path错误排查
问题根因
两个报错和第二个下拉框不渲染是连锁问题,核心出在两个常见写法错误上:
- 90%概率是你遍历
questionsFormArray的时候,formGroupName没加方括号,写成了静态的formGroupName="i"。这种写法下Angular不会解析*ngFor导出的索引变量i,会直接拿字符串'i'当路径找控件,自然抛出Cannot find control with path: 'questions -> i'的错误。 - 剩下10%的概率是你
*ngFor遍历错了对象,遍历的是原始业务数组questionsArr,不是questions.controls,导致DOM循环的索引和FormArray内实际的控件索引错位,第一个项索引0碰巧对上了能渲染,后面的索引和控件不匹配,直接渲染失败。 - 至于
questions -> i -> question的报错,没有特殊原因,就是你TS里初始化每个问题的FormGroup时,漏写了question这个FormControl,要么就是字段名拼错了——比如你定义的时候写的是content,模板里绑的是formControlName="question",路径对不上自然报错。
修复方法
- 先改模板里FormArray的遍历绑定,必须给
formGroupName加方括号做动态绑定,而且确保遍历的是FormArray的控件集合,不是原始数据:
错误写法(触发当前问题的典型写法):
正确写法:<div formArrayName="questions"> <!-- 要么没加方括号,要么遍历错了数组 --> <div *ngFor="let item of questionsArr; let i = index" formGroupName="i"> <select formControlName="type">...</select> <app-option [formGroup]="item"></app-option> </div> </div><div formArrayName="questions"> <!-- 遍历FormArray的controls,formGroupName加方括号绑定索引变量 --> <div *ngFor="let q of questions.controls; let i = index" [formGroupName]="i"> <select formControlName="type"> <option *ngFor="let t of types" [value]="t.value">{{t.label}}</option> </select> <app-option [group]="q"></app-option> </div> </div> - 对齐TS里的FormGroup结构,确保模板里用到的所有控件都在初始化时声明,别漏字段:
改完这两处两个报错都会消失,第二个问题的type下拉框也能正常渲染。// 初始化FormArray的时候每个组的字段要和模板绑定的名字完全一致 this.form = this.fb.group({ questions: this.fb.array( this.questionsArr.map(questionItem => this.fb.group({ type: [questionItem.type, Validators.required], question: [questionItem.question, Validators.required], // 之前大概率漏了这行 options: this.fb.array( (questionItem.options || []).map(opt => this.fb.control(opt)) ), answer: [questionItem.answer] })) ) })
关于子组件不写formArrayName的疑问
能不能正常运行完全看你子组件获取控件的方式:
- 如果你像上面示例那样,直接把当前循环到的FormGroup实例通过Input传给子组件,子组件内部直接用传入的实例获取
optionsFormArray做绑定,那父组件完全不需要写formArrayName="options",不会报错。这种方式是直接传控件引用,不需要靠DOM上的表单层级按名字找控件,自然不受路径声明的影响。 - 只有当你不给子组件传控件实例,完全靠
formControlName/formArrayName顺着DOM上的表单层级逐层找控件的时候,才需要严格在每一层DOM节点上声明对应的formGroupName、formArrayName,缺一层就会报找不到控件的错。 - 你现在这么写没触发报错,就说明子组件是直接拿Input传入的FormGroup实例操作控件的,写法本身没问题,不用硬加formArrayName声明。
内容的提问来源于stack exchange,提问作者Karan Patel
相关产品推荐
相关产品推荐

