Angular CDK 覆盖模块:CanDeactivateGuard 应该启动自定义模式



>更新:

我已经根据下面绝望@Blind答案进行了重构。它现在使用来自Angular CDK的覆盖模块。这是守卫的代码:

@Injectable({
providedIn: 'root',
})
export class PendingChangesGuard
implements CanDeactivate<ComponentCanDeactivate> {
content = 'A simple string content modal overlay';
constructor(private overlayService: OverlayService) {}
canDeactivate(
component: ComponentCanDeactivate
): boolean | Observable<boolean> {
return component.canDeactivate()
? true
: this.openConfirmDialog(this.content);
}
openConfirmDialog(content: TemplateRef<any> | ComponentType<any> | 
string) {
const ref = this.overlayService.open(this.content, null);
return ref.afterClosed$.subscribe((res) => {});
}
}

问题是这一行返回订阅,我的守卫必须返回布尔值或可观察值:

return ref.afterClosed$.subscribe((res) => {});

下面是覆盖服务类:

@Injectable({
providedIn: 'root',
})
export class OverlayService {
constructor(private overlay: Overlay, private injector: Injector) {}
open<R = any, T = any>(
content: string | TemplateRef<any> | Type<any>,
data: T
): OverlayRef<R> {
const configs = new OverlayConfig({
hasBackdrop: true,
panelClass: ['modal', 'is-active'],
backdropClass: 'modal-background',
});
const overlayRef = this.overlay.create(configs);
const myOverlayRef = new OverlayRef<R, T>(overlayRef, content, 
data);
const injector = this.createInjector(myOverlayRef, this.injector);
overlayRef.attach(new ComponentPortal(OverlayComponent, null, 
injector));
return myOverlayRef;
}
createInjector(ref: OverlayRef, inj: Injector) {
const injectorTokens = new WeakMap([[RaOverlayRef, ref]]);
return new PortalInjector(inj, injectorTokens);
}
}

下面是覆盖类:

export interface OverlayCloseEvent<R> {
type: 'backdropClick' | 'close';
data: R;
}
// R = Response Data Type, T = Data passed to Modal Type
export class OverlayRef<R = any, T = any> {
afterClosed$ = new Subject<OverlayCloseEvent<R>>();
constructor(
public overlay: OverlayRef,
public content: string | TemplateRef<any> | Type<any>,
public data: T // pass data to modal i.e. FormData
) {
overlay.backdropClick().subscribe(() => 
this._close('backdropClick', null));
}
close(data?: R) {
this._close('close', data);
}
private _close(type: 'backdropClick' | 'close', data: R) {
this.overlay.dispose();
this.afterClosed$.next({
type,
data,
});
this.afterClosed$.complete();
}
}

关于如何重构openConfirmDialog((以返回我需要的内容的任何提示?

您不能在该守卫中返回布尔值,因为打开模态不足以定义它应该给出的结果。您必须等待用户输入,这意味着您的防护canDeactivate应返回PromiseObservable。不幸的是,您当前的模式对话框太简单,无法支持该用例。基本上,您希望拥有类似.afterClosed()的东西,它返回Promise<boolean>Observable<boolean>然后当用户单击是/否时,您必须解决承诺或向主题发出值并完成它。然后,您可以轻松地从守卫那里返回.afterClosed()的结果。但是您需要为此重构您的服务和模式。当然,您可以将afterClosed()作为模态组件上的方法,但您不希望将其所有方法公开给守卫或任何使用它的方法,因此一个好的做法是引入一个仅公开您想要公开的内容的DialogRef。但是,如果这个问题已经解决了,为什么要重新发明轮子呢?有一个惊人的角度模块称为@angular/cdk,您可以使用它轻松创建一个非常智能的模态对话框。您可以查看这篇文章。

你能稍微重构一下吗?

canDeactivate(
component: ComponentCanDeactivate
): boolean | Observable<boolean> {
const _v = component.canDeactivate();
if (!_v) {
this.openConfirmDialog();
}
return _v;
}

最新更新