Как объединить несколько наблюдаемых значений с помощью forkjoin, чтобы получить одно наблюдаемое значение

Пытаюсь получить Observable<boolean> для моего Guard, объединив два значения Observable<boolean> через forkJoin.

Я пробовал этот подход раньше:

    isAllowedToEditSession(sessionId: number): Observable<boolean> {
        const isAllowed$: BehaviorSubject<boolean> = new BehaviorSubject(false);
        const hostName = this.authService.getMyDisplayName();
        this.sessionProxyService.getSessionById(sessionId).subscribe(session => {
          if (session.hostName === hostName) {
            isAllowed$.next(true);
          }
        });
        this.userService.isUserAdmin().subscribe(isAdmin => 
   isAllowed$.next(isAdmin));
        return isAllowed$.asObservable();
      }

Это сработало, но только потому, что this.userService.isUserAdmin() является BehaviorSubject и уже имело сохраненное значение, поэтому оно выполнялось синхронно.

Это мой текущий подход, который не дает мне того результата, на который я надеялся.

isAllowedToEditSession(sessionId: number): Observable<boolean> {
    const hostName = this.authService.getMyDisplayName();
    const isAllowed$ = forkJoin(
      this.sessionProxyService.getSessionById(sessionId),
      this.userService.isUserAdmin()
    ).pipe(
      map(([session, isAdmin]) => {
        const isHost = session.hostName === hostName;
        console.log(isHost || isAdmin);
        return isHost || isAdmin;
      })
    );
    return isAllowed$;
  }

isAllowed$ распознается как Observable<boolean>, но неправильно выдает эти значения.

ОБНОВЛЕНИЕ

Это работает (см. принятый ответ для объяснения):

isAllowedToEditSession(sessionId: number): Observable<boolean> {
    const hostName = this.authService.getMyDisplayName();
    const isAllowed$ = forkJoin(
      this.sessionProxyService.getSessionById(sessionId), //pipe(take(1)) not needed here
      this.userService.isUserAdmin().pipe(take(1))
    ).pipe(
      map(([session, isAdmin]) => {
        const isHost = session.hostName === hostName;
        return isHost || isAdmin;
      })
    );
    return isAllowed$;
  }

person BingeCode    schedule 22.07.2019    source источник
comment
Как это не работает? Вы получаете сообщение об ошибке?   -  person Reactgular    schedule 22.07.2019
comment
Извините, я должен был указать ожидаемое поведение. Это не работает, потому что не выдает true, хотя в моем случае либо isHost, либо isAdmin должны возвращать true. Но принятый ответ был решением моей проблемы.   -  person BingeCode    schedule 23.07.2019


Ответы (1)


forkJoin требует, чтобы все исходные Observable выдали хотя бы одно значение, а затем завершились. И это проблема у вас есть. Вы используете BehaviorSubject внизу, который не завершится, пока вы не вызовете .complete().

Вы должны сделать, например, это:

if (session.hostName === hostName) {
  isAllowed$.next(true);
  isAllowed$.complete();
}

Так что это зависит от того, как реализованы getSessionById() и isUserAdmin(). Вы также можете направить их обоих с помощью take(1) перед передачей их в forkJoin.

person martin    schedule 22.07.2019
comment
Благодарю вас! Это была моя проблема. Однако у меня есть вопрос: автоматически ли завершаются http-вызовы? Потому что мне не нужно было .pipe(take(1)) на this.sessionProxyService.getSessionById(sessionId), что является вызовом get. Я обновил свой пост с окончательным решением. - person BingeCode; 23.07.2019
comment
Да, если вы имеете в виду HttpClient в Angular, они выполняются автоматически. - person martin; 23.07.2019