如何异步订阅matdialog服务以启用candeactivate Guard? [英] How to subscribe asynchronously to matdialog service for candeactivate guard?

查看:84
本文介绍了如何异步订阅matdialog服务以启用candeactivate Guard?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用角度形式验证实现了candeactivate警卫. 如果用户单击ngForm字段.并尝试导航到其他选项卡,用户将获得一个自定义确认弹出窗口,该窗口将显示放弃更改?"并返回true或false.

I have implemented candeactivate guard using angular forms validation. If user clicks on an ngForm Field. and tries to navigate to different Tab, user will get a custom confirmation Popup, which will say "Discard Changes ? " and returns true or false.

这是我的保镖

import { NgForm } from "@angular/forms";
import { ComponentCanDeactivate } from './component-can-deactivate';

export abstract class FormCanDeactivate extends ComponentCanDeactivate {

abstract get form(): NgForm;

canDeactivate(): boolean {
    return this.form.submitted || !this.form.dirty;
}
}

Component Guard

Component Guard

import { HostListener } from "@angular/core";

export abstract class ComponentCanDeactivate {

abstract canDeactivate(): boolean;

@HostListener('window:beforeunload', ['$event'])
unloadNotification($event: any) {
    if (!this.canDeactivate()) {
        $event.returnValue = true;
    }
}
}

现在这是我用于确认弹出窗口的代码.我的问题是,如果我使用默认的Confirm()方法(下面的代码中的注释行),它将弹出窗口,并询问YES或NO,效果很好.但是,如果我在此处使用自定义材质弹出窗口", 我必须订阅afterclosed()方法,该方法异步执行,而我必须等到该方法执行后再继续.我该如何实现?

Now here is my code for confirmation popup. My problem here is if I use default confirm() method (commented line in below code), it gives windows popup,and asks for YES or NO, which works perfect. But if I use Custom Material Popup here, I have to subscribe to afterclosed() method, which performs asynchronously, whereas I have to wait till this method executes before proceeding. How can I achieve this ?

import { Injectable } from '@angular/core';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { MatMenuTrigger, MatDialog } from '@angular/material';
import { Observable } from 'rxjs/Observable';
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): boolean {

    if (!component.canDeactivate()) {
        // return confirm('You have unsaved changes! If you leave, your changes will be lost');

        const dialogRef = this.modalService.open(ConfirmationComponent, {});
        dialogRef.afterClosed().subscribe(res => {
            if (res == 'OK') {
                return true;
            } else {
                return false;
            }
        });
    }
        return true;
    }
}

然后从模态中返回确定",如下所示

And from the modal I am returning 'OK' like below

constructor(private dialogRef: MatDialogRef<ConfirmationComponent>) { }

btnOk() {
   this.dialogRef.close('OK');

}

感谢您的帮助.

我已在组件中扩展了formdeactivate

I have extended formdeactivate in my component

export class EditFormComponent extends FormCanDeactivate implements OnInit {

@ViewChild('form', { static: true }) form: NgForm;

constructor(){super();}
}

Stackblitz链接: https://angular-custom-popup-candeactivate.stackblitz.io

Stackblitz Link :https://angular-custom-popup-candeactivate.stackblitz.io

推荐答案

您的问题

您想要一种可重用的方式来提示用户,然后再离开包含脏表单的组件.

Your problem

You want a reusable way to prompt users before navigating away from a component containing a dirty form.

要求:

  • 表格是否干净没有提示
  • 如果用户要退出,导航将继续
  • 如果用户不想退出,导航将被取消

我花了一点时间来了解您的解决方案,我发现这是处理多个组件的一种优雅方法.

Once I took a little time to understand your solution, I can see it is an elegant way of handling multiple components.

您的设计大约是这样:

export abstract class ComponentCanDeactive {
  abstract canDeactivate(): boolean;
}

export abstract class FormCanDeactivate extends ComponentCanDeactivate {
  abstract get form(): NgForm;

  canDeactivate(): boolean {
    return this.form.submitted || !this.form.dirty;
  }
}

如果要将其应用于组件,只需扩展FormCanDeactivate类.

If you want to apply this to a component, you just extend the FormCanDeactivate class.

您可以使用Angular CanDeactivate路由防护程序来实现它.

You implement it using the Angular CanDeactivate route guard.

export class CanDeactivateGuard implements CanDeactivate<ComponentCanDeactivate> {
  canDeactivate(component: ComponentCanDeactivate): boolean {
    return component.canDeactivate();
  }
}

您将此添加到路由中的相关路由中.我假设您了解了所有这些工作原理,因为您已为其提供了代码和演示.

You add this to the relevant routes in your routing. I assume that you understand how all of this works, since you provided the code and demo for it.

如果您只是想在组件具有脏表单时阻止路由停用,那么您已经解决了问题.

If you simply want to prevent route deactivation when a component has a dirty form, you have already solved the problem.

您现在希望在用户离开肮脏的表格之前给他们一个选择.您使用同步javascript confirm实现了此功能,但是您想使用异步的Angular Material对话框.

You now want to give the user a choice before they navigate away from a dirty form. You implemented this with a synchronous javascript confirm, but you want to use the Angular Material dialog, which is asynchronous.

首先,由于您要异步使用它,因此需要从防护中返回异步类型.您可以返回PromiseObservable. Angular Material对话框返回Observable,所以我将使用它.

Firstly, since you are going to use this asynchronously, you need to return an asynchronous type from your guard. You can return either a Promise or Observable. The Angular Material dialog returns an Observable, so I'll use that.

现在只是设置对话框并返回可观察的关闭功能的一种情况.

It's now simply a case of setting up the dialog and returning the observable close function.

deactivate-guard.ts

deactivate-guard.ts

constructor(private modalService: MatDialog) {}

canDeactivate(component: ComponentCanDeactivate):  Observable<boolean> {
  // component doesn't require a dialog - return observable true
  if (component.canDeactivate()) {
    return of(true);
  }

  // set up the dialog
  const dialogRef = this.modalService.open(YesNoComponent, {
    width: '600px',
    height: '250px', 
  });

  // return the observable from the dialog  
  return dialogRef.afterClosed().pipe(
    // map the dialog result to a true/false indicating whether
    // the route can deactivate
    map(result => result === true)
  );    
}

其中YesNoComponent是自定义对话框组件,您已将其创建为对话框的包装器.

Where YesNoComponent is a custom dialog component you have created as a wrapper around the dialog.

export class YesNoComponent {

  constructor(private dialogRef: MatDialogRef<YesNoComponent>  ) { }

  Ok(){
    this.dialogRef.close(true);
  }

  No(){
    this.dialogRef.close(false);
  }
}

演示: https://stackblitz.com/edit/angular-custom -popup-candeactivate-mp1ndw

这篇关于如何异步订阅matdialog服务以启用candeactivate Guard?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆