BehaviorSubject не сразу меняет значение

Я создаю настраиваемую службу входа с AuthGuard из Angular. У меня есть SessionService, у которого есть такие методы, как login() или onUserLoggedIn(), который в основном возвращает BehaviorSubject с текущим значением статуса пользователя (вошел / не вошел в систему). На основе этого сервиса я создал реализацию сервиса AuthGuard implements CanActivate. Я вызываю метод onUserLoggedIn и проверяю текущее значение в теме. Проблема здесь в том, что в login значение метода изменяется после AuthGuard вызова onUserLoggedIn. Поэтому при первой попытке я получаю ложное значение от BehaviorSubject, но когда я пытаюсь второй раз, я получил истинное значение.

Как я могу изменить реализацию этих двух сервисов, чтобы получить текущую ценность с первой попытки?

AuthGuard:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
    : Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    console.log('auth');

    return this.sessionService.onUserLoggedIn()
      .pipe(
        map(res => {
          console.log('res', res);
          return res;
        }),
        take(1),
        tap(allowed => {
          console.log(allowed);
          if (!allowed) {
            this.router.navigate(['/login']);
          }
        })
      );
  }

SessionService:

private isLoggedIn = new BehaviorSubject(false);

  constructor(private apiService: ApiService) {
  }

  login(user: User): Observable<any> {
    console.log('hello before');
    return this.apiService.post(`${BASE_URL}/login`, user)
      .pipe(
        tap((token: Token) => {
          this.isLoggedIn.next(true);
          localStorage.setItem('token', token.token);
          console.log('hello');
        })
      );
  }

  onUserLoggedIn() {
    return this.isLoggedIn;
  }

Первая попытка идет с печатным значением:

  • SessionService.ts: 19 привет раньше
  • AuthGuard.ts: 17 автори.
  • AuthGuard.ts: 22 разрешения false
  • AuthGuard.ts: 27 ложных
  • SessionService.ts: 25 привет

Второй (который, как я ожидаю, будет первым):

  • SessionService.ts: 19 привет раньше
  • AuthGuard.ts: 17 автори.
  • AuthGuard.ts: 22 разрешения true
  • AuthGuard.ts: 27 истинных
  • SessionService.ts: 25 привет

person Jan Testowy    schedule 28.05.2019    source источник
comment
Когда ваш компонент входа в систему выполняет перенаправление?   -  person Tzannetos Philippakos    schedule 28.05.2019


Ответы (2)


Природа BehaviorSubject заключается в том, что он сразу же генерирует заданное значение, когда вы подписываетесь.

Поэтому в зависимости от вашего варианта использования используйте Subject. Также используйте оператор пропуска, чтобы пропустить первое значение.

return this.sessionService.onUserLoggedIn()
      .pipe(
        take(1),
        map(res => {
          console.log('res', res);
          return res;
        }),
        tap(allowed => {
          console.log(allowed);
          if (!allowed) {
            this.router.navigate(['/login']);
          }
        })
      );
  }

используйте startsWith(false) в других компонентах.

person Veeraragavan    schedule 28.05.2019
comment
У меня должен быть BehaviorSubject, потому что в других компонентах мне нужно иметь по умолчанию любое значение - person Jan Testowy; 28.05.2019
comment
Любая необходимость иметь здесь значение по умолчанию. Если вы действительно хотите false в качестве значения по умолчанию, используйте startWith (false) в других компонентах. - person Veeraragavan; 28.05.2019
comment
бывший. то, что я отображаю в заголовке (например, вкладки), сделано для значения по умолчанию. Но в любом случае .. это не цель этого вопроса;) - person Jan Testowy; 28.05.2019

Можете попробовать вернуть его как Observable?

onUserLoggedIn() {
        return this.isLoggedIn.asObservable();
      }
person Muhammad Kamran    schedule 28.05.2019
comment
трубопровод, который он автоматически возвращает, - это asObservable. Пока за наблюдаемым стоит объект BehaviorSubject, будет возвращено текущее значение. - person Tzannetos Philippakos; 28.05.2019