如何异步订阅matdialog服务以启用candeactivate Guard? [英] How to subscribe asynchronously to matdialog service for 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.
首先,由于您要异步使用它,因此需要从防护中返回异步类型.您可以返回Promise
或Observable
. 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屋!