如何为CanDeactivate守卫异步订阅MatDialog服务?
Angular CanDeactivate守卫配合Material自定义弹窗的异步处理方案
我懂你的困扰——原生confirm()是同步的,守卫能直接拿到结果完成判断,但Material弹窗是异步的,用subscribe的话,守卫方法会直接走完逻辑返回默认值,根本等不到用户的选择结果,对吧?
其实Angular的CanDeactivate守卫支持返回Observable<boolean>类型,这就是解决异步弹窗的核心!你不需要在守卫内部订阅弹窗的关闭事件,而是把这个Observable直接返回给Angular框架,它会自动等待这个流完成,再根据最终结果决定是否允许导航操作。
修改你的CanDeactivateGuard代码:
import { Injectable } from '@angular/core'; import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { MatDialog } from '@angular/material'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { ComponentCanDeactivate } from './component-can-deactivate'; import { ConfirmationComponent } from 'src/app/core/modals/confirmation/confirmation.component'; @Injectable() export class CanDeactivateGuard implements CanDeactivate<ComponentCanDeactivate> { constructor(private modalService: MatDialog) { } canDeactivate(component: ComponentCanDeactivate): Observable<boolean> | boolean { // 如果没有未保存的更改,直接允许导航 if (component.canDeactivate()) { return true; } // 打开自定义弹窗,返回Observable<boolean>交由Angular处理 const dialogRef = this.modalService.open(ConfirmationComponent, {}); return dialogRef.afterClosed().pipe( map(res => res === 'OK') // 把弹窗返回的'OK'映射为true,其他情况均返回false ); } }
关键改动说明:
- 调整方法返回类型为
Observable<boolean> | boolean,同时兼容同步返回和异步Observable场景 - 移除
subscribe逻辑,改用pipe(map(...))将弹窗的返回值转换为布尔值,直接返回这个Observable - Angular路由守卫会自动订阅该Observable,等待用户完成弹窗操作后,再执行对应的导航逻辑
你的其他代码(FormCanDeactivate、ComponentCanDeactivate基类以及组件继承部分)都无需修改,保持原样即可。这样用户点击弹窗的"OK"按钮就会允许导航离开,点击取消或关闭弹窗则会留在当前页面。
内容的提问来源于stack exchange,提问作者Chetan Birajdar
相关产品推荐
相关产品推荐

