TypeScript使用Mat-Dialog实现两级级联删除弹窗的方案与失效排查
问题根因
- 索引i失效问题:第一级弹窗确认后才触发第二级弹窗,两个弹窗的触发存在时间差,该时间段内如果
dataSource.data数组发生了变化(比如其他行被新增/删除、表格切换分页、重新排序),你最初点击删除时拿到的索引i对应的行数据就会发生错位,甚至出现索引越界,导致传给删除接口的参数错误,请求直接失败。 - 返回值校验逻辑异常:两级弹窗的
afterClosed()回调返回值都命名为res,内层参数会屏蔽外层变量。同时如果你的第二级弹窗关闭时返回的不是布尔真值(比如用户点击取消返回false、填写的原因是空字符串,弹窗默认返回空值),内层的if(res)判断会直接不通过,删除逻辑自然不会执行。 - 嵌套订阅的异步风险:RxJS中嵌套订阅属于不推荐的写法,没有统一的错误处理链路,只要其中某一步出现异常(比如弹窗组件报错、接口返回错误),整个逻辑会静默失败,很难排查问题。
两级删除弹窗最优实现方案
核心优化思路是用RxJS操作符打平异步流,避免嵌套订阅,提前锁定要删除的行数据,不依赖随时可能变化的索引,同时补充统一错误处理逻辑,参考实现代码如下:
import { filter, switchMap, catchError, EMPTY } from 'rxjs'; deleteRow(i: any) { // 提前锁定要删除的行数据,不依赖后续可能变化的索引i const targetDeleteRow = this.dataSource.data[i]; this.dialogService .openConfigDialog('你确认要删除该文件吗?') .afterClosed() .pipe( // 第一级弹窗点确认才继续执行,否则直接中断流 filter(firstConfirmRes => !!firstConfirmRes), // 打平第二级弹窗的异步流 switchMap(() => this.reason.openReasonDialog("请填写删除原因").afterClosed()), // 第二级弹窗返回有效原因才继续执行 filter(deleteReason => !!deleteReason), // 打平删除接口的异步流 switchMap(() => { const deleteRowRequest = { IstValues: [targetDeleteRow] }; return this.istManagementService.deleteRecord(this.inputTable, deleteRowRequest); }), // 统一捕获全链路的异常 catchError(err => { console.error('删除失败,请重试', err); // 此处可补充错误提示弹窗逻辑 return EMPTY; }) ) .subscribe(() => { // 删除成功后用对象匹配找索引,避免中间数据源变化导致删错行 const finalDelIndex = this.dataSource.data.findIndex(item => item === targetDeleteRow); if (finalDelIndex > -1) { this.dataSource.data.splice(finalDelIndex, 1); this.dataSource._updateChangeSubscription(); } }) } refresh(): void { window.location.reload()}
内容的提问来源于stack exchange,提问作者leandroter7
相关产品推荐
相关产品推荐

