如果满足某些条件,RXJS停止可观察链的传播

时间:2018-10-16 23:16:07

标签: angular rxjs observable angular-observable angular-router-guards

简介

我正在尝试使用共享服务中的Observable在self.filteredReasons = ko.computed(function() { return ko.utils.arrayFilter(self.Reasons(), function(reason) { if(reason.Id !== 1) { return true; } }); }); 中创建路由保护,该服务保留了当前用户角色的字符串值。
问题显然出在我的思维从应许转向可观察。

  

到目前为止,我所做的是基于启发式和尝试与错误方法,但是   我杀死了浏览器感谢danday74

尝试(感谢@ danday74改进)

RxJS sequence equvalent to promise.then()?的帮助下,我已经将我想做的事情翻译成该链:

<select data-bind="options: filteredReasons ,  optionsText: 'Title', optionsValue: 'Id', value: SelectReason, optionsCaption: 'Choose..'"></select>

问题

如果Angular2+,如何停止可观察链的进一步传播?如果满足这样的条件,我需要返回该布尔值,并确保之后不调用canActivate(route: ActivatedRouteSnapshot): Observable<boolean> | boolean { return this.auth.isRoleAuthenticated(route.data.roles) .mergeMap((isRoleAuthenticated: boolean) => { return isRoleAuthenticated ? Observable.of(true) : this.auth.isRole(Roles.DEFAULT_USER); }) .do((isDefaultUser: boolean) => { const redirectUrl: string = isDefaultUser ? 'SOMEWHERE' : 'SOMEWHERE_ELSE'; this.router.navigate([redirectUrl]); }) .map((isDefaultUser: boolean) => { return false; }); } 运算符块。
局限性是必须从isRoleAuthenticated = true后卫返回布尔值。

3 个答案:

答案 0 :(得分:1)

您从第一个mergeMap返回的任何内容都会传递到第二个mergeMap,这样它就不会停止进一步传播。如果要停止传播,请使用过滤器(尽管在这种情况下可能会导致挂起)。

仅在返回Observable时才使用mergeMap,但无需从第二个mergeMap返回Observable。只要做:

  .mergeMap((isRoleAuthenticated: boolean) => {
    if (isRoleAuthenticated) {
      return Observable.of(true)
    }
    return this.auth.isRole(Roles.DEFAULT_USER)
  })
  .tap((isDefaultUser: boolean) => {
    if (isDefaultUser) {
      this.router.navigate(['SOMEWHERE'])
    } else {
      this.router.navigate(['SOMEWHERE_ELSE'])
    }
  })
  .map((isDefaultUser: boolean) => {
    return false
  })

此外,您正在使用RxJs v5语法,但应使用v6。在v6中,操作符-mergeMap,tap,map-用逗号分隔在管道中。

可能路由器导航阻止了最终返回并导致挂起?注释掉它,看看它是否可以停止挂起。

不确定这会完全解决您的问题,但希望在凌晨1点有一些有用的见识

我假设这些返回Observables:

  • this.auth.isRoleAuthenticated
  • this.auth.isRole(Roles.DEFAULT_USER)

如果他们不这样做,您将遇到问题。

解决方案

您可以创建一个由收集的Observable结果组成的对象,而不是专注于停止链,然后进一步传播该对象,从而解决问题:

canActivate(route: ActivatedRouteSnapshot): Observable<boolean> | boolean {
    return this.auth.getRole()
        .mergeMap((role: string) => {
            return this.auth.isRoleAuthorized(route.data.roles)
                .map((authorized: boolean) => ({
                    role: role,
                    authorized: authorized
                }));
        })
        .do((markers: { role: string, authorized: boolean }) => {
            const redirectUrl: string = markers.role === Roles.DEFAULT_USER ? 'SOMEWHERE' : 'SOMEWHERE_ELSE';
            this.router.navigate([redirectUrl]);
        })
        .map((markers: { role: string, authorized: boolean }) => {
            return markers.authorized;
        });
}

答案 1 :(得分:1)

do()运算符仅适用于next通知,因此,如果您不想处理.mergeMap之后的内容,可以使用filter()进行过滤:< / p>

return this.auth.isRoleAuthenticated(route.data.roles)
  .mergeMap((isRoleAuthenticated: boolean) => {
    return isRoleAuthenticated ? Observable.of(true) : this.auth.isRole(Roles.DEFAULT_USER);
  })
  .filter(authenticated => authenticated !== true)

但是,您似乎可以只返回Observable.empty()而不是Observable.of(true),因为这只会发出complete通知,没有next项,因此没有任何内容传递给do()

.mergeMap((isRoleAuthenticated: boolean) => {
  return isRoleAuthenticated ? Observable.empty() : this.auth.isRole(Roles.DEFAULT_USER);
})

答案 2 :(得分:0)

您可以返回Observable.of(true)而不是返回Observable.empty(),它会完成而不会发出任何值。因此不会执行以下链。