Angular for循环内subscribe仅最后一行赋值生效的正确实现方式
问题根因
只有最后一行下拉框赋值成功是两个问题共同导致的:
- 闭包索引异常:若循环变量没有做块级作用域隔离,所有异步订阅回调触发时循环已经执行完成,回调里拿到的索引会固定指向最后一项
- 赋值时序错误:
getCFTType接口的作用是加载当前行cMFID下拉框的可选选项,必须等接口返回、选项列表完成渲染后再执行setValue操作,否则Angular表单无法匹配到对应选项,会直接丢弃赋值结果。前序行接口返回时选项尚未就绪就会赋值失败,最后一行因为执行时机靠后,选项加载完成才会赋值成功
*额外语法错误:原代码中rTC.controls[i].get['triggerTypeId']写法错误,get是Angular表单控件的取值方法,必须通过小括号调用,正确写法为rTC.controls[i].get('triggerTypeId')
修复方案
推荐直接使用forEach遍历表单控件,自带块级作用域可以彻底规避索引闭包问题,同时严格遵守「先绑选项再赋值」的时序:
if (rTC) { rTC.controls.forEach((formGroup, rowIndex) => { const currentTriggerTypeId = formGroup.get('triggerTypeId').value; this.baseService.getCFTType(currentTriggerTypeId, this.baseService.productId).subscribe(options => { // 第一步:绑定接口返回的下拉选项到当前行cMFID控件,按自身业务实际逻辑替换对应绑定代码 // formGroup.get('cMFID').setConfig({ options: options }); // 第二步:选项绑定完成后再赋值,传入emitEvent:false避免触发不必要的值变更校验 const targetValue = savedData.repReg.repT[rowIndex].cMFID; formGroup.get('cMFID').setValue(targetValue, { emitEvent: false, onlySelf: true }); }); }); }
进阶优化(表单行数较多时推荐)
如果表单单页行数较多,可以用forkJoin合并所有下拉选项请求,等所有接口全部返回后再逐行绑定选项、赋值,从根源上避免逐行请求的时序错乱问题:
// 组件顶部按需导入rxjs操作符 import { forkJoin } from 'rxjs'; if (rTC) { // 构造所有行的接口请求数组 const reqList = rTC.controls.map(formGroup => { const triggerTypeId = formGroup.get('triggerTypeId').value; return this.baseService.getCFTType(triggerTypeId, this.baseService.productId); }); // 等所有接口全部返回后统一处理 forkJoin(reqList).subscribe(allOptions => { allOptions.forEach((rowOptions, index) => { const currentGroup = rTC.controls[index]; // 绑定当前行下拉选项 // currentGroup.get('cMFID').setConfig({ options: rowOptions }); // 赋值选中项 const targetVal = savedData.repReg.repT[index].cMFID; currentGroup.get('cMFID').setValue(targetVal, { emitEvent: false }); }); }); }
内容的提问来源于stack exchange,提问作者vamsi
相关产品推荐
相关产品推荐

