如何处理警卫中显示的模态
Posted
技术标签:
【中文标题】如何处理警卫中显示的模态【英文标题】:How to deal with a modal shown in a guard 【发布时间】:2019-07-08 19:39:18 【问题描述】:我有一个像这样实现的守卫:
@Injectable()
export class CustomerGuard implements CanActivate
constructor(
private authService: AuthenticationService,
private dialog: MatDialog
)
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean
if (this.authService.isCustomer)
return true;
const dialog = this.dialog.open(SigninModalComponent,
data:
errorMessage: this.authService.isLoggedIn ?
'You don\t have access to this page, please use an appropriate account' :
'Please authenticate to access this page'
);
return dialog.afterClosed().pipe(
map(() =>
return this.authService.isCustomer;
)
);
当我在浏览器的地址栏中输入未经授权的路由时,服务器端渲染会显示一个惰性模式,然后当客户端接管时,会显示另一个工作模式,我可以在其中成功验证并访问请求的路由。
问题是服务器端渲染的模态永远不会消失......
对于这个问题是否有一个干净的解决方案,并不意味着不在服务器端显示模式?
【问题讨论】:
客户端路由配置中是否存在unauthorized route
?如果是,服务器端渲染是如何触发的?如果没有,路由守卫不应该被执行。如果我遗漏了什么,请告诉我
@planet_hunter 当然,路由存在于服务器端和客户端。我不明白你的意思。
好的,你能指定你在浏览器窗口中输入的unauthorized route
URL吗?
【参考方案1】:
我会使用 DI 来帮助您解决这个问题。我利用他们网站上的Angular Universal 示例创建了一个示例。
首先创建一个令牌:
app/tokens.ts
import InjectionToken from '@angular/core';
export let RENDERED_BY_TOKEN = new InjectionToken('renderedBy');
更新 app.module.ts
以使用此令牌通过 DI 容器提供值:
import RENDERED_BY_TOKEN from './tokens';
@NgModule(
.
.
.
providers: [
.,
.,
provide: RENDERED_BY_TOKEN, useValue: 'client'
],
.
.
.
export class AppModule
更新 app.server.module.ts
以使用此令牌通过 DI 容器提供值:
import RENDERED_BY_TOKEN from './tokens';
@NgModule(
.
.
.
providers: [
.,
.,
provide: RENDERED_BY_TOKEN, useValue: 'server'
],
.
.
.
export class AppServerModule
然后在你的代码中的其他地方(我使用了一个组件,但你会将它放在你的路由保护中),使用该令牌注入值:
app.component.ts
import Component, Inject from '@angular/core';
import RENDERED_BY_TOKEN from './tokens';
@Component(
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
)
export class AppComponent
title = 'Tour of Heroes';
renderedBy;
constructor(@Inject(RENDERED_BY_TOKEN) val: string)
this.renderedBy = val;
app.component.html
<h1>title</h1>
<h5>renderedBy</h5>
<nav>
<a routerLink="/dashboard">Dashboard</a>
<a routerLink="/heroes">Heroes</a>
</nav>
<router-outlet></router-outlet>
<app-messages></app-messages>
如果您运行此程序,您将看到 h5
元素从“服务器”更新为“客户端”,表明它正在工作。您可以在 if 语句中在您的守卫中使用此值,以不在服务器渲染上显示该对话框。
更新
在阅读这篇文章时,我注意到了一种更简单的方法。似乎 Angular 本身无需自定义令牌即可为您提供这些信息。
在 Guard 中,您可以使用以下内容对其进行更新:
import PLATFORM_ID, Inject from '@angular/core';
import isPlatformBrowser from '@angular/common';
constructor(@Inject(PLATFORM_ID) private platformId: Object)
const isServer = !isPlatformBrowser(platformId);
更新2
鉴于对问题的澄清,我能够完成此任务的唯一方法似乎不太理想,但这是迄今为止我发现的唯一可行的方法。
document.querySelectorAll('.cdk-overlay-container').forEach(dialog => dialog.remove());
作为参考,我为这个答案所做的所有工作都在 GitHub repo 中。
【讨论】:
感谢您的回答。我知道我可以有条件地加载服务器模式。我的问题是关于显示服务器端模式并在客户端接管时隐藏它。 虽然这个解决方案不适合我,但如果在悬赏到期时仍然没有其他答案,我会奖励你的研究工作 解决方案不满意怎么办?也许还有其他事情可以做以使其适用于您的场景。 我只是说就像你说的那样,解决方案“不太理想”,我们不应该直接在 Angular 中使用 javascript 的 API 明白。我也会这么想的。正如我对其他答案和docs 的评论一样,在这种情况下,它似乎是必需的。以上是关于如何处理警卫中显示的模态的主要内容,如果未能解决你的问题,请参考以下文章
如何处理 Twitter Bootstrap 中的模态关闭事件?