如何处理警卫中显示的模态

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 中的模态关闭事件?

如何处理弹出、模态、可调整大小的表单

使用模态确认删除时表的id值为null时如何处理错误?

Translucent Modal ViewController - 如何处理旋转

如何处理后台线程上显示的 LWUIT 对话框

如何处理来自用户输入的偶数数组并在 C++ 中用空格显示它们