我已经使用角度形式验证实现了candeactivate警卫。 如果用户单击ngForm字段。并尝试导航到其他选项卡,用户将获得一个自定义确认弹出窗口,该窗口将显示“放弃更改?”并返回true或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
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()方法,该方法异步执行,而我必须等到该方法执行后再继续。我该如何实现?
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;
}
}
然后从模态中返回“确定”,如下所示
constructor(private dialogRef: MatDialogRef<ConfirmationComponent>) { }
btnOk() {
this.dialogRef.close('OK');
}
感谢您的帮助。
编辑:
我已经在组件中停用了form停用
export class EditFormComponent extends FormCanDeactivate implements OnInit {
@ViewChild('form', { static: true }) form: NgForm;
constructor(){super();}
}
Stackblitz链接:https://angular-custom-popup-candeactivate.stackblitz.io
答案 0 :(得分:2)
您想要一种可重用的方式来提示用户,然后才离开包含脏表单的组件。
要求:
我花了一点时间来了解您的解决方案,我发现这是处理多个组件的一种优雅方式。
您的设计大约是这样:
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
类。
您可以使用Angular CanDeactivate
路由防护程序来实现它。
export class CanDeactivateGuard implements CanDeactivate<ComponentCanDeactivate> {
canDeactivate(component: ComponentCanDeactivate): boolean {
return component.canDeactivate();
}
}
您将此添加到路由中的相关路由。我假设您了解了所有这些工作原理,因为您已为其提供了代码和演示。
如果您只想在组件具有脏表单时阻止路由停用,那么您已经解决了问题。
您现在希望在用户离开肮脏的表格之前给他们一个选择。您使用同步JavaScript confirm
实现了此功能,但是您想使用异步的Angular Material对话框。
首先,由于您要异步使用它,因此需要从防护中返回异步类型。您可以返回Promise
或Observable
。 Angular Material对话框返回一个Observable
,所以我将使用它。
现在只是设置对话框并返回可观察的关闭功能的一种情况。
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
是自定义对话框组件,您已将其创建为对话框的包装器。
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