RxJS过滤器阵列数组

时间:2018-03-08 15:01:42

标签: rxjs

我试图对rxjs中的数组数组执行过滤。请考虑以下事项:

    function guard1(): boolean | Observable<boolean> {}
    function guard2(): boolean | Observable<boolean> {}
    function guard3(): boolean | Observable<boolean> {}

    const routes = [
        { name: 'Foo', canActivate: [guard1, guard2] },
        { name: 'Bar', canActivate: [guard3] },
        { name: 'Moo' }
    ];

我想将routes数组过滤为仅返回true的路由 从内部数组canActivate的结果组合或如果它没有canActivate,我希望它不被过滤掉。

让我们说guard1返回trueguard2返回false,我希望路由Foo不在过滤列表中。

我对此进行了一次尝试,但它并没有完全符合我的期望:

    this.filteredRoutes = forkJoin(of(routes).pipe(
            flatMap((route) => route),
            filter((route) => route.canActivate !== undefined),
            mergeMap((route) =>
                of(route).pipe(
                    mergeMap((r) => r.canActivate),
                    mergeMap((r) => r()),
                    map((result) => {
                        console.log('here', result, route);
                        return route;
                    })
                )
        )));

如果我在RXJS之外写这个,代码可能看起来像这样:

    this.filteredRoutes = [];
    for (const route of this.routes) {
        if (route.canActivate) {
            let can = true;
            for (const act of route.canActivate) {
                let res = inst.canActivate();
                if (res.subscribe) {
                    res = await res.toPromise();
                }
                can = res;
                if (!can) {
                    break;
                }
            }
            if (can) {
                this.filteredRoutes.push(route);
            }
        } else {
            this.filteredRoutes.push(route);
        }
    }

谢谢!

1 个答案:

答案 0 :(得分:4)

我确定还有其他(可能更好的方法来解决这个问题,但它有效......

from(routes).pipe(
    concatMap((route) => {
      // handle if nothing is in canActivate
      if (!route.canActivate || route.canActivate.length === 0) {
        // create an object that has the route and result for filtering
        return of({route, result: true})
      };

      const results = from(route.canActivate).pipe(
        // execute the guard
        switchMap(guard => {
          const result: boolean | Observable<boolean> = guard();
          if (result instanceof Observable) {
            return result;
          } else {
            return of(result);
          }
        }),
        // aggregate the guard results for the route
        toArray(),
        // ensure all results are true
        map(results => results.every(r => r)),
        // create an object that has the route and result for filtering
        map(result => ({route, result})),
      );

      return results;
    }),
    // filter out the invalid guards
    filter(routeCanActivateResult => routeCanActivateResult.result),
    // return just the route
    map(routeCanActivateResult => routeCanActivateResult.route),
    // turn it back into an array
    toArray()
  )
  // verify it works
  .subscribe(routes => routes.forEach(r => console.log(r.name)));

此外,这是stackblitz中的一个工作示例。