使用defaultIfEmpty()仍无法在Angular can中激活

时间:2019-05-10 13:34:40

标签: angular rxjs

我在一项服务中有一个观察员:

hasAccess$: Observable<boolean>;

这被分配在一个单独的组件中。它包含filter(),并且永远不会发出false,而只会发出true。因此,如果它为假,则不会发出。

我需要在路由防护中使用它。所以我尝试了:

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$。如果不是这样,则会引发错误,因为您无法传送未定义的内容。没有错现在很奇怪的是,它发出了false:

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

两者都通过管道传输到defaultIfEmpty(false)。警卫队为什么不散发武器?

更新:感谢@martin指出defaultIfEmpty()仅在完成时发出。我现在也意识到,first()如果不发出任何东西,将无法完成它。我想我需要弄清楚当它什么都不发出时如何使其完成。

2 个答案:

答案 0 :(得分:1)

您可以将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。

答案 1 :(得分:0)

想出了一个解决方案:

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> {
    return this.service.hasAccess$.pipe(
      merge(of(false)),
      first()
    );
  }
  1. 首先从hasAccess$移出,
  2. 它与可观察到的false合并,
  3. 它使用first(),因此,如果hasAccess$发出true,则采用它,否则,如果不发出任何东西,则防护措施为false。