angular - Angular CDK 覆盖模块:CanDeactivateGuard 应该启动自定义模式
问题描述
更新:
我根据下面@Blind Despair 的回答进行了重构。它现在使用来自 Angular CDK 的覆盖模块。这是Guard的代码:
@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) => {});
}
}
问题是这一行正在返回订阅,而我的守卫必须返回布尔值或 Observable:
return ref.afterClosed$.subscribe((res) => {});
这是OverlayService类:
@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
应该返回 aPromise
或 an Observable
。不幸的是,您当前的模式对话框太简单,无法支持该用例。基本上,您希望获得类似.afterClosed()
which 返回的内容Promise<boolean>
,或者Observable<boolean>
当您的用户单击是/否时,您必须解决一个承诺或向主题发出一个值并完成它。然后你可以很容易地.afterClosed()
从你的后卫那里返回结果。但是您需要为此重构您的服务和模式。当然你可以拥有afterClosed()
作为模态组件上的方法,但您不想将其所有方法公开给守卫或任何会使用它的方法,因此一个好的做法是引入 a DialogRef
,它只会公开您想要公开的内容。但是,如果这个问题已经解决了,为什么还要重新发明轮子呢?有一个令人惊叹的 Angular 模块@angular/cdk
,您可以使用它轻松地创建一个非常智能的模态对话框。你可以查看这篇文章。
推荐阅读
- java - 模块从 IntelliJ 的项目资源管理器中消失
- app-store-connect - 删除 testflight 内部测试器和外部测试器
- php - 如何将唯一标识符添加到 php 数组中特定键的相同值
- spring - WAS 8.5.5.2:在类路径上未检测到 spring webapplicationinitializer 类型
- web-services - 如何在 MySql 的单个名称列中添加多个表 id 并在 CakePHP 中使用 type_id 加入?
- c# - 可以避免分配 out 值吗?
- python - pyplot.scatter(c='red')。无效的语法?
- css - 颜色荧光笔不适用于 Sublime Text 3 Win 10
- ios - Sharing two image and two text in UIActivityViewController is not working properlly
- php - Laravel Page is not working on Image upload