Использование defaultIfEmpty () все еще не излучает в Angular canActivate guard - PullRequest
0 голосов
/ 10 мая 2019

У меня есть наблюдаемое в сервисе:

hasAccess$: Observable<boolean>;

Это назначается в отдельном компоненте. Он содержит filter() и никогда не будет выдавать ложь, только истину. Так что если оно ложно, оно не излучает.

Мне нужно использовать его в охране маршрута. Итак, я попробовал:

canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> {
    return this.service.hasAccess$.pipe(
      defaultIfEmpty(false),
      tap(access => {
        console.log({access}); // never logs
      }),
      first()
    );
  }
  • Я использовал defaultIfEmpty(), чтобы обеспечить выдачу значения
  • Я использовал tap(), чтобы регистрировать, если что-то случается (этого не происходит)
  • Я использовал first(), потому что наблюдаемые, возвращаемые в охранниках , должны завершиться .

Я гарантировал, что this.service.hasAccess$ будет назначен. Выдает ошибку, если это не так, потому что вы не можете передать неопределенное. Там нет ошибки. Теперь странная вещь, это испускает ложь:

return of().pipe(
  defaultIfEmpty(false),
  tap(access => {
    console.log({access});
  }),
  first()
);

Оба переданы по каналу defaultIfEmpty(false). Почему охранник не излучает?

Обновление : Спасибо @martin за указание, что defaultIfEmpty() испускается только после завершения. Также теперь я понимаю, что first() не завершит работу, если ничего не испустит. Я думаю, мне нужно выяснить, как сделать его завершенным, когда он ничего не излучает.

Ответы [ 2 ]

1 голос
/ 10 мая 2019

Вы можете добавить startWith(false) оператор к вашей hasAccess$ наблюдаемой, чтобы он всегда что-то излучал:

hasAccess$: Observable<boolean> = this.someServiceCall().pipe(startWith(false));

Или вы можете ввести тайм-аут в методе canActivate():

canActivate(
  next: ActivatedRouteSnapshot,
  state: RouterStateSnapshot): Observable<boolean> {
  return this.service.hasAccess$.pipe(
    timeout(5000),
    first(),
    catchError(() => of(false))
  );
}

На вашем месте я бы использовал первый метод, если hasAccess$ получает свое значение из хранилища или синхронного источника, и метод 2, если он выполняет асинхронный вызов.

0 голосов
/ 10 мая 2019

Разобрался с решением:

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> {
    return this.service.hasAccess$.pipe(
      merge(of(false)),
      first()
    );
  }
  1. Он начинается с выделения из hasAccess$,
  2. Он сливается с наблюдаемой false,
  3. Используется first(), поэтому, если hasAccess$ испускает истину, он принимает его, иначе, если он ничего не испускает, охранник становится ложным.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...