RXJS Остановить распространение наблюдаемой цепи, если выполнено определенное условие - PullRequest
0 голосов
/ 17 октября 2018

Введение

Я пытаюсь создать защиту маршрута в Angular2+, используя Observable из общего сервиса, который содержит строковое значение текущей роли пользователя.
Проблема, очевидно, заключается в том, чтобы изменить свое мнениеот обещаний к наблюдаемым.

То, что я сделал до сих пор, основано на эвристике и методе проб и ошибок, но я врезался в стену, убив браузер Решено благодаря danday74

.

Попытка (улучшена благодаря @ danday74)

С помощью последовательности RxJS, эквивалентной обещанию .then ()? я перевел то, что хочусделать в эту цепочку:

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?Мне нужно вернуть это логическое значение, если такое условие выполнено, и убедиться, что операторский блок .do не вызывается после.
Ограничение состоит в том, что логическое значение должно быть возвращено из canActivate guard.

Ответы [ 3 ]

0 голосов
/ 17 октября 2018

Оператор do() работает только с уведомлениями next, поэтому, если вы не хотите обрабатывать то, что идет после .mergeMap, вы можете отфильтровать его с помощью filter():

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);
})
0 голосов
/ 17 октября 2018

Вместо возврата Observable.of(true), вы можете вернуть Observable.empty(), который будет просто завершен, не выдавая никаких значений.Таким образом, следующие цепочки не будут выполнены.

0 голосов
/ 17 октября 2018

Все, что вы возвращаете из первой mergeMap, передается во вторую mergeMap, поэтому дальнейшее распространение не будет остановлено.Если вы хотите остановить распространение, используйте фильтр (хотя это может вызвать зависание в этом сценарии).

Вы используете mergeMap только тогда, когда возвращаете Observable, но нет необходимости возвращать Observable из 2-го mergeMap.Просто сделайте:

  .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 час

1011 * Я предполагаю, что эти возвращаемые Observables:
  • this.auth.isRoleAuthenticated
  • this.auth.isRole (Roles.DEFAULT_USER)

Если этого не произойдет, у вас возникнут проблемы.

Solution

Вместо того, чтобы сосредоточиться на остановке цепочки, вы можете создать объект, состоящий из результатов собранных Observables по пути, и распространять его дальше, что решает проблему:

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;
        });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...