You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中CanDeactivate自定义确认弹窗异常问题求助

Angular未保存数据自定义确认弹窗问题

我在Angular应用中实现未保存数据的自定义确认弹窗时遇到两个问题:

  • 方案1:弹窗正常弹出,但所有背景元素消失,其余功能正常
  • 方案2:背景元素正常,但不该显示弹窗时也会弹出,推测是返回Observable时未等待客户端响应导致的

以下是两种方案的CanDeactivate Guard实现代码、AlertDialogManager服务代码以及调用方法:

第一种方案代码

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { TranslateService } from '@ngx-translate/core';
import { AlertDialogManager } from 'compiler-modules';


export interface ComponentCanDeactivate {
  canDeactivate: () => boolean | Observable<boolean>;
  pendingChangesMessage?: string;
}

@Injectable({
  providedIn: 'root'
})
export class PendingChangesGuardGuard implements CanDeactivate<ComponentCanDeactivate> {

  private defaultPendingMessage: string;

  constructor(translateService: TranslateService, private ad: AlertDialogManager) {
    translateService.get('GENERIC.PENDING_CHANGES')
      .subscribe(t => this.defaultPendingMessage = t);
  }

  canDeactivate(component: ComponentCanDeactivate,
                currentRoute: ActivatedRouteSnapshot,
                currentState: RouterStateSnapshot,
                nextState?: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    return component.canDeactivate() ? true : this.ad.confirm("ty", component.pendingChangesMessage || this.defaultPendingMessage)
    
  }

}

第二种方案代码

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { TranslateService } from '@ngx-translate/core';
import { AlertDialogManager } from 'compiler-modules';
import { first } from 'rxjs/operators';

export interface ComponentCanDeactivate {
  canDeactivate: () => boolean | Observable<boolean>;
  pendingChangesMessage?: string;
}

@Injectable({
  providedIn: 'root'
})

export class PendingChangesGuardGuard implements CanDeactivate<ComponentCanDeactivate> {

  private defaultPendingMessage: string;

  constructor(translateService: TranslateService, private ad: AlertDialogManager) {
    translateService.get('GENERIC.PENDING_CHANGES')
      .subscribe(t => this.defaultPendingMessage = t);
  }

  canDeactivate(component: ComponentCanDeactivate,
                currentRoute: ActivatedRouteSnapshot,
                currentState: RouterStateSnapshot,
                nextState?: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

                  let t :boolean;
              this.ad.confirm("ty", component.pendingChangesMessage || this.defaultPendingMessage).subscribe(res => (t = res))
    return component.canDeactivate() ? true :
      t;
  }

}

AlertDialogManager服务代码

import { Injectable, TemplateRef } from '@angular/core';
import { MatDialog } from '@angular/material';
import { Observable } from 'rxjs/Observable';

import { AlertDialogViewComponent } from './alert-dialog-view/alert-dialog-view.component';
import { AlertConfig, AlertInputData } from './alert-dialog.models';

@Injectable({
  providedIn: 'root'
})
export class AlertDialogManager {

  constructor(private dialog: MatDialog) { }

  alert(title: string, description: string, buttonText: string = 'OK',
        bodyTemplateRef: TemplateRef<any> = null, bodyTemplateContext: any = null, config: AlertConfig = null): Observable<void> {
    const alertRef = this.dialog.open<AlertDialogViewComponent, AlertInputData, void>(AlertDialogViewComponent, {
      disableClose: true,
      panelClass: 'dialog-container-small',
      data: {
        title: title,
        description: description,
        buttonText: buttonText,
        type: 'alert',
        bodyTemplateRef: bodyTemplateRef,
        bodyTemplateContext: bodyTemplateContext
      },
      ...config
    });

    return alertRef.afterClosed();
  }

  confirm(title: string, question: string, buttonText: string = 'OK', cancelButtonText: string = 'Anuluj',
          bodyTemplateRef: TemplateRef<any> = null, bodyTemplateContext: any = null, config: AlertConfig = null): Observable<boolean> {
    const alertRef = this.dialog.open<AlertDialogViewComponent, AlertInputData, boolean>(AlertDialogViewComponent, {
      disableClose: true,
      panelClass: 'dialog-container-small',
      data: {
        title: title,
        description: question,
        buttonText: buttonText,
        cancelButtonText: cancelButtonText,
        type: 'confirm',
        bodyTemplateRef: bodyTemplateRef,
        bodyTemplateContext: bodyTemplateContext
      },
      ...config
    });

    return alertRef.afterClosed();
  }

}

调用方法

@HostListener('window:beforeunload')
canDeactivate(): Observable<boolean> | boolean {
  return !this.issueViewComponent ? true : this.issueViewComponent.canDeactivate();
}

截图说明

  • 新增笔记视图:正常的页面展示状态,包含所有界面元素
  • 存在未保存更改时背景消失:弹窗弹出后,页面背景元素全部消失,仅弹窗可见

内容的提问来源于stack exchange,提问作者Kacper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:58:22