Observable‹Observable‹T›› в Observable‹T›

Новичок RxJS здесь. Использование Angular 6. Пытаюсь понять, как получить Observable<T> из Observable<Observable<T>>. Не уверен, что это действительно так, и пытается понять это концептуально, однако это кажется простой проблемой.

Я просмотрел switchMap, flatMap, forJoin, однако не думаю, что они соответствуют моим потребностям.

То, что я пытаюсь сделать, это защита маршрута Angular, которая не позволит пользователям получить доступ к маршруту, если у них нет необходимых разрешений. 2 зависимости — это профиль пользователя, из которого он получает информацию, которая затем используется для получения его разрешений. Это сочетание приводит к проблеме Observable of 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;
            }
        ));
    }
}

Большое спасибо!!


person Ross    schedule 03.04.2019    source источник


Ответы (1)


В нынешнем виде вы возвращаете Observable из функции hasPermissionObservable, которая будет обернута в Observable из map operator.

Вы можете просмотреть mergeMap/flatMap operator или contactMap 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: Сопоставьте значения с внутренним наблюдаемым, подпишитесь и испускайте по порядку. Пример из ссылки 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;
}
person Community    schedule 03.04.2019
comment
Вау, спасибо большое! Я пробовал кучу разных вещей с операторами карты, однако я просто не мог правильно понять синтаксис/и т.д. Многие примеры angular устарели (более старая версия RxJS), а в документации RxJS не было примеров с достаточным количеством комбинаций, чтобы продемонстрировать проблему. Спасибо еще раз! - person Ross; 03.04.2019