Angular FormArray调用removeAt删除测试用例仅首个按钮生效问题
问题原因
你代码的核心问题是两层索引混淆:
- 第一层是
questionsFormArray的索引,代表第几个题目,你当前初始化的表单中只有1个题目,所以该层合法索引只有0 - 第二层是每个题目下的
testcasesFormArray的索引,代表该题目下第几个测试用例
你现在直接把测试用例的索引当成了questions数组的索引去取值,当测试用例数量超过1个时,取questions.controls[index]就会拿到undefined,访问undefined的controls属性就抛出了对应的报错。
修复方案
1. 修正HTML模板
补全外层questions数组的循环,明确区分题目索引qIndex和测试用例索引tIndex,删除/新增操作时传入正确的索引:
<form [formGroup]="parentForm"> <!-- 外层遍历题目数组,拿到题目索引qIndex --> <div formArrayName="questions" *ngFor="let question of questionsArray.controls; index as qIndex"> <div [formGroupName]="qIndex"> <div formArrayName="testcases"> <!-- 内层遍历当前题目下的测试用例,拿到测试用例索引tIndex --> <div class="form-control grid grid-cols-2 justify-between mb-8 w-xl" *ngFor="let testcase of getTestcaseControl(qIndex); index as tIndex" [formGroupName]="tIndex" > <div class="flex"> <div class="form-control m-0"> <label class="label"> <span class="label-text">输入值</span> </label> <input type="text" placeholder="2 3 4" formControlName="input" /> <label class="label"> <p *ngIf="checkFormInput(testcase, 'input')" class="invalid-feedback" > 请输入该测试用例的输入值 </p> </label> </div> <div class="form-control m-0"> <label class="label"> <span class="label-text">输出值</span> </label> <div class="flex items-center"> <input type="text" placeholder="12 34 84" formControlName="output" /> <!-- 删除时传入两个索引参数 --> <img src="../../../../assets/images/course/course-leaderboard-avatars/cancel.png" class="w-6 h-6 cursor-pointer py-auto mt-2 mx-2" alt="删除图标" (click)="onDeleteTestcase(qIndex, tIndex)" /> </div> <label class="label"> <p *ngIf="checkFormInput(testcase, 'output')" class="invalid-feedback" > 请输入该测试用例的输出值 </p> </label> </div> </div> <div class="form-control m-0 w-6"></div> </div> </div> <!-- 新增测试用例时传入当前题目索引 --> <div class="flex justify-end mr-4"> <button class="btn btn-secondary" type="button" (click)="onAddTestcase(qIndex)"> 新增测试用例 </button> </div> </div> </div> </form>
注意:新增按钮需要加
type="button",否则会触发表单默认提交行为。
2. 优化组件逻辑,简化类型转换
先给组件添加两个通用getter,避免重复的类型转换代码:
// 获取题目数组 get questionsArray(): FormArray { return this.parentForm.get('questions') as FormArray; } // 根据题目索引获取对应测试用例数组 getTestcasesArray(qIndex: number): FormArray { return this.questionsArray.at(qIndex).get('testcases') as FormArray; }
3. 修正原有方法
修正获取测试用例列表的方法
getTestcaseControl(qIndex: number) { return this.getTestcasesArray(qIndex).controls; }
修正删除测试用例方法
onDeleteTestcase(qIndex: number, tIndex: number) { this.getTestcasesArray(qIndex).removeAt(tIndex); }
简化新增测试用例方法
onAddTestcase(qIndex: number) { this.getTestcasesArray(qIndex).push( this.fb.group({ input: ['', [Validators.required('请输入该测试用例的输入值')]], output: ['', [Validators.required('请输入该测试用例的输出值')]], }) ); }
内容的提问来源于stack exchange,提问作者tamir
相关产品推荐
相关产品推荐

