【问题标题】:Observable<Observable<T>> to Observable<T>Observable<Observable<T>> 到 Observable<T>
【发布时间】:2019-08-24 09:46:34
【问题描述】:

这里是 RxJS 新手。使用 Angular 6。试图弄清楚如何从 Observable&lt;Observable&lt;T&gt;&gt; 获取 Observable&lt;T&gt;。不确定这是否有效并且难以从概念上理解它,但这似乎是一个简单的问题。

我研究过 switchMap、flatMap、forJoin,但我认为它们不符合我的需求。

我正在尝试做的是一个 Angular 路由守卫,它将阻止用户访问路由,除非他们拥有必要的权限。 2个依赖项是一个用户配置文件,用于获取他们的信息,然后用于获取他们的权限。这种混合导致了 Observable 的 Observable 问题。这是我得到的:

export class AuthPermissionsRouteGuard implements CanActivate {
    constructor(
    private router: Router,
    private authService: AuthPermissionsService,
    private openIdService: AuthOpenIdService) {}

    /**Navigates to route if user has necessary permission, navigates to '/forbidden' otherwise */
    canActivate(routeSnapshot: ActivatedRouteSnapshot): Observable<boolean> {
        return this.canNavigateToRoute(routeSnapshot.data['permissionId'] as number);
    }

    /**Waits on a valid user profile, once we get one - checks permissions */
    private canNavigateToRoute(permissionId: number): Observable<boolean> {
        const observableOfObservable = this.openIdService.$userProfile
            .pipe(
                filter(userProfile => userProfile ? true : false),
                map(_ => this.hasPermissionObservable(permissionId)));

            // Type Observable<Observable<T>> is not assignable to Observable<T> :(
        return observableOfObservable;
    }

    /**Checks if user has permission to access desired route and returns the result. Navigates to '/forbidden' if no permissions */
    private hasPermissionObservable(permissionId: number): Observable<boolean> {
        return this.permissionsService.hasPermission(permissionId).pipe(
            map(hasPermission => {
                if (!hasPermission) {
                    this.router.navigate(['/forbidden']);
                }

                return hasPermission;
            }
        ));
    }
}

非常感谢!!

【问题讨论】:

    标签: angular rxjs observable angular-route-guards


    【解决方案1】:

    就目前而言,您正在从 hasPermissionObservable 函数返回一个 Observable,它将被包装在来自 map operator 的 observable 中。

    您需要查看mergeMap/flatMap operatorcontactMap operator

    MergeMap:当您希望展平内部可观察对象但又想手动控制内部订阅数量时,最好使用此运算符。 Learn RXJS 链接中的示例:

    // RxJS v6+
    import { of } from 'rxjs';
    import { mergeMap } from 'rxjs/operators';
    
    // emit 'Hello'
    const source = of('Hello');
    // map to inner observable and flatten
    const example = source.pipe(mergeMap(val => of(`${val} World!`)));
    // output: 'Hello World!'
    const subscribe = example.subscribe(val => console.log(val));
    
    

    ContactMap:将值映射到内部 observable,按顺序订阅和发出。 Learn RXJS 链接中的示例:

    // RxJS v6+
    import { of } from 'rxjs';
    import { concatMap } from 'rxjs/operators';
    
    // emit 'Hello' and 'Goodbye'
    const source = of('Hello', 'Goodbye');
    // example with promise
    const examplePromise = val => new Promise(resolve => resolve(`${val} World!`));
    // map value from source into inner observable, when complete emit result and move to next
    const example = source.pipe(concatMap(val => examplePromise(val)));
    // output: 'Example w/ Promise: 'Hello World', Example w/ Promise: 'Goodbye World'
    const subscribe = example.subscribe(val =>
      console.log('Example w/ Promise:', val)
    );
    

    所以对于你的例子:

    /**Waits on a valid user profile, once we get one - checks permissions */
    private canNavigateToRoute(permissionId: number): Observable<boolean> {
      const observableOfObservable = this.openIdService.$userProfile
        .pipe(
           filter(userProfile => userProfile ? true : false),
           concatMap(_ => this.hasPermissionObservable(permissionId))); // <- try changes here
    
      // Type Observable<Observable<T>> is not assignable to Observable<T> :(
      return observableOfObservable;
    }
    

    【讨论】:

    • 哇,非常感谢!我已经用地图运算符尝试了很多不同的东西,但是我无法正确使用语法/等。许多角度示例已过时(较旧的 RxJS 版本),并且 RxJS doco 没有具有足够组合的示例来证明该问题。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 2016-11-05
    • 2021-12-01
    相关资源
    最近更新 更多