angular - 如何处理守卫中显示的模态

标签 angular typescript angular-universal

我有一个像这样实现的守卫:

@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;
      })
    );
  }
}

当我在浏览器的地址栏中键入未经授权的路由时,服务器端呈现会显示一个惰性模式,然后当客户端接管时,会显示另一个工作模式,我可以在其中成功验证和访问所请求的路由。

问题是服务器端呈现的模态永远不会消失...

这个问题是否有一个干净的解决方案,不会暗示不在服务器端显示模态?

最佳答案

我会使用 DI 来帮助您解决这个问题。我使用了 Angular Universal从他们的网站上采样以创建示例。

首先创建一个token: app/tokens.ts

import { InjectionToken } from '@angular/core';

export let RENDERED_BY_TOKEN = new InjectionToken('renderedBy');

更新 app.module.ts 以使用此 token 通过 DI 容器提供值:

import { RENDERED_BY_TOKEN } from './tokens';
@NgModule({
.
.
.
providers: [
  .,
  .,
  { provide: RENDERED_BY_TOKEN, useValue: 'client' }
],
.
.
.
export class AppModule { }

更新 app.server.module.ts 以使用此 token 通过 DI 容器提供值:

import { RENDERED_BY_TOKEN } from './tokens';
@NgModule({
.
.
.
providers: [
  .,
  .,
  { provide: RENDERED_BY_TOKEN, useValue: 'server' }
],
.
.
.
export class AppServerModule { }

然后在你代码的其他地方(我使用了一个组件,但你会把它放在你的路由守卫中),使用该 token 注入(inject)值:

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 本身就可以为您提供此信息,而无需自定义 token 。

在 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 - 如何处理守卫中显示的模态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54696147/

相关文章:

typescript - 在 TypeScript 中增加默认导出?

typescript - 如何禁用TSLint警告-深度导入

javascript - Angular 动态表单,包含从 JSON 获取的元素组

angular - 无法绑定(bind)到 'ngFormModel',因为它不是已知的 native 属性,在更新 Angular2 rc3 之后

angular - 使用 ionic 4 在后台模式处于事件状态时运行函数

typescript - 使用 typescript 和 browserify/gulp 严重破坏了 Sourcemaps

typescript - 如何从对象数组中提取值

angular - 在 TestBed 模块中创建时,NGRX 和 NGXS 会创建单独的 Store 实例吗?

angular - 找不到路由时检索 404 状态。 Angular 6+ 和通用

Angular 9 通用 - 运行错误 : can not read property 'type' of undefined - TokenStream