升级Angular 15后dialogRef.beforeClosed出现调用栈溢出错误
Angular 15升级后Dialog无限循环问题的解决方案
问题原因
Angular 15升级后,Angular Material的MatDialogRef.beforeClosed() Observable行为发生了变化:调用dialogRef.close()会触发beforeClosed()再次发出通知。你的原有代码在beforeClosed()的订阅里调用close(),导致每次close()都会触发新的beforeClosed()事件,进而重复调用close(),最终引发无限循环和栈溢出错误。
贴合Angular 14原有行为的解决方案
方案1:用take(1)限制订阅仅执行一次
通过RxJS的take(1)操作符,让订阅只响应第一次beforeClosed()事件,执行完close()后自动取消订阅,避免后续触发循环:
import { take } from 'rxjs'; // 替换原有代码 this.dialogRef.beforeClosed().pipe(take(1)).subscribe(() => { this.dialogRef.close(this.selectedRows); });
这个方案最贴近你原有代码的逻辑:仅在第一次关闭触发时设置结果,不会重复执行。
方案2:直接在关闭触发点调用close()
如果你的对话框有明确的关闭触发源(比如确定按钮),可以直接在这些触发点调用close()传递结果;对于遮罩、叉号这类系统关闭方式,可通过对话框配置disableClose: true禁用,然后自定义关闭按钮统一处理:
// 对话框打开时的配置 const dialogRef = this.dialog.open(YourDialogComponent, { disableClose: true, // 禁用系统默认关闭方式 // 其他配置 }); // 对话框组件内的关闭按钮点击事件 onClose() { this.dialogRef.close(this.selectedRows); }
这种方式更清晰,完全避免依赖beforeClosed()的订阅逻辑,从根源上杜绝循环。
方案3:判断关闭结果是否已设置
在beforeClosed()的订阅中,仅当关闭结果为undefined(即未主动设置结果的情况)时才调用close(),避免重复触发:
this.dialogRef.beforeClosed().subscribe((result) => { // 仅当无主动设置的关闭结果时,才设置选中行作为结果 if (result === undefined) { this.dialogRef.close(this.selectedRows); } });
当用户通过系统方式(如遮罩)关闭时,result为undefined,此时设置结果;当主动调用close(selectedRows)时,result为已设置的值,不会重复执行close()。
内容的提问来源于stack exchange,提问作者Mohammad Dayyan
相关产品推荐
相关产品推荐

