Как бороться с модалом, показанным в карауле - PullRequest
0 голосов
/ 14 февраля 2019

У меня реализована защита, подобная этой:

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

Когда я набираю неавторизованный маршрут в адресной строке моего браузера, рендеринг на стороне сервера показывает инертный модальный режим, затем, когда клиентская сторона берет верхдругой работающий модал показан, где я могу успешно пройти аутентификацию и получить доступ к запрошенному маршруту.

Проблема в том, что модал на стороне сервера никогда не исчезает ...

Есть ли чистое решение дляэта проблема, которая не подразумевает не показывать модал на стороне сервера?

1 Ответ

0 голосов
/ 19 февраля 2019

Я бы использовал 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, чтобы не отображать этот диалог на сервере.

UPDATE

При прохождении этой записи язаметил более простой способ.Похоже, что сама 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);
}

UPDATE2

Учитывая прояснение вопроса, единственный способ, которым я смог достичь этого, кажется немного менее идеальным, но это единственное, что я нашел до сих пор работать.

document.querySelectorAll('.cdk-overlay-container').forEach(dialog => dialog.remove());

Для справки, все мои работы для этого ответа находятся в репозитории GitHub .

...