簡體   English   中英

Rxjs 嵌套觀察者未執行

[英]Rxjs Nested observer is not executed

我已經閱讀了很多關於如何在 RxJs 和 Angular 中嵌套觀察者的文檔、文章和不同的線程,但我仍然遺漏了一些東西並且最終無法得到結果。

這是我的代碼:

頁面.ts

export class LiabilitiesPage implements OnInit {
     constructor(
        private liabilityService: LiabilityService,
        private router: Router
     ) {}

     refreshLiabilities() {
      // Get the liabilities
      console.log('refreshing') // passing there
      this.liabilityService.getAllLiabilities().subscribe(
      (response: Liability[]) => {
        console.log(response); // <=== Never pass there !

        if (response) {
          this.liabilities = response;
        } else {
          // empty response code
        }
      }, error => {
        // response error code (never passing there either)
      }
  }
}

liability.service.ts

// all the needed imports

@Injectable({
  providedIn: 'root'
})
export class LiabilityService {
  constructor(
    private authService: AuthService,
    private http: HttpClient,
    ) {}

  // first try : Do not send the http request
  getAllLiabilities(): Observable<Liability[]> {
    return this.authService.getOptions()
        .pipe(
            tap(options => this.http.get<Liability[]>(this.url + 'me/', options))
        );
  }

    // try 2 : Doesn't work either
    getAllLiabilities(): Observable<Liability[]> {
      return this.authService.getOptions()
        .pipe(
            switchMap(options => this.http.get<Liability[]>(this.url + 'me/', options)), // at this point I tried pretty much every operators (map, mergeMap etc.)
            withLatestFrom()
        ); 
  }
    /* this code was working before that I transformed the authService.getOptions in observable (it was just returning the options synchronyously before)
getAllLiabilities(): Observable<Liability[]> {
  return this.http.get<Liability[]>(this.url + 'me/', this.authService.getOptions());
  }*/
}

授權服務.ts


public getOptions(): Observable<any> {
      return new Observable((observer) => {
          this.storage.get('authToken').then((token) => {
              console.log('passing') // Pass here
              if (token && typeof token.auth_token !== 'undefined') {
                  console.log('passing') // pass here as well
                  this.isLoggedIn = true;
                  this.token = token.auth_token;
              }
              // it is returning the value
              return {
                  headers: this.headers.set('Authorization', 'Bearer ' + this.token),
                  params: new HttpParams()
              };
          })
      });
    }

我嘗試了幾乎所有可能的運算符組合以使其在 liabilityService 中工作但沒有成功。

問題:

問題是我的page.ts訂閱了this.http.get<Liability[]>(this.url + 'me/', options)觀察者,但沒有觸發 xhr 請求。 http get observer 永遠不會執行,我不明白我在那里遺漏了什么。

我剛剛開始試驗 Angular,但如果我理解正確,操作員應該進行映射和展平,但這看起來永遠不會發生。

獎金問題:

我不明白為什么初始代碼:

return this.http.get<Liability[]>(this.url + 'me/', this.authService.getOptions());

正在返回一個Observable<Liability[]>

並使用 switchMap:

switchMap(options => this.http.get<Liability[]>(this.url + 'me/', options))

它返回一個Observable<HttpEvent<Liability[]>>

如果有人有線索並有時間回答我,那就太棒了

您在 promise 回調then()中遇到問題:

this.storage.get('authToken').then((token) => {
    return something; // this won't work.
})

相反,您可以使用from ,它將您的 promise convert為可觀察的。

import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

public getOptions(): Observable<any> {
    return from(this.storage.get('authToken')).pipe(map(token => {
        return headers with token.
    }));
}

所以你可以像這樣重寫你的代碼:

授權服務:

private token: string | null = null;


public getOptions(): Observable<any> {
  return this.getToken().pipe(
    map(token => {
      return {
        headers: this.headers.set('Authorization', 'Bearer ' + token),
        params: new HttpParams()
      };
    })
  );
}


private getToken(): Observable<string | null> {
  if (this.token) {
    return of(this.token);
  }

  return from(this.storage.get('authToken')).pipe(
    map(token => token?.authToken || null),
    tap(token => this.token = token)
  );
}

然后你可以使用開關圖:

getAllLiabilities(): Observable<Liability[]> {
  return this.authService.getOptions().pipe(
    switchMap(options => this.http.get<Liability[]>(this.url + 'me/', options))
  );
}

更新

獲取HttpEvent<T>的原因是因為當.get()的重載接收到any object 時,它會將 http 事件處理完全交給您。 如果你想讓它返回提供的元素類型,你必須滿足適當的重載。 你可以這樣做:

我們沒有返回整個選項,而是只返回標頭,這應該足夠了,因為我們真的沒有足夠的東西來說明選項的 rest。

授權服務

private token: string | null = null;

public createTokenHeaders(): Observable<HttpHeaders> {
  const headers = new HttpHeaders();
  return addToken(headers);
}

public addToken(headers: HttpHeaders): Observable<HttpHeaders> {
  return this.getToken().pipe(
    map(token => headers.set('Authorization', 'Bearer ' + (token || '')))
  );
}

private getToken(): Observable<string | null> {
  if (this.token) {
    return of(this.token);
  }

  return from(this.storage.get('authToken')).pipe(
    map(token => token?.authToken || null),
    tap(token => this.token = token)
  );
}

然后像這樣使用它:

getAllLiabilities(): Observable<Liability[]> {
  const url = this.url + 'me/';
  const headers = new HttpHeaders();
  return this.authService.addToken(headers).pipe(
    switchMap(updatedHeaders => this.http.get<Liability[]>(url, { headers: updatedHeaders }))
  );
}

要么:

getAllLiabilities(): Observable<Liability[]> {
  const url = this.url + 'me/';
  return this.authService.createTokenHeaders().pipe(
    switchMap(headers => this.http.get<Liability[]>(url, { headers }))
  );
}

注意:確保使用從調用 addToken 返回的標頭。 重用您自己的實例化headers將不起作用,因為設置 header 總是會返回一個新的HttpHeaders object。它是不可變的。

StackBlitz 示例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM