簡體   English   中英

使用 TypeScript 從 Angular2 中的 http 數據鏈接 RxJS Observables

[英]Chaining RxJS Observables from http data in Angular2 with TypeScript

在過去 4 年愉快地使用 AngularJS 1.* 之后,我目前正在嘗試自學 Angular2 和 TypeScript! 我不得不承認我討厭它,但我確信我的尤里卡時刻即將來臨......無論如何,我已經在我的虛擬應用程序中編寫了一個服務,它將從我編寫的提供 JSON 的虛假后端獲取 http 數據。

import {Injectable} from 'angular2/core';
import {Http, Headers, Response} from 'angular2/http';
import {Observable} from 'rxjs';

@Injectable()
export class UserData {

    constructor(public http: Http) {
    }

    getUserStatus(): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get('/restservice/userstatus', {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    getUserInfo(): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get('/restservice/profile/info', {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    getUserPhotos(myId): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get(`restservice/profile/pictures/overview/${ myId }`, {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    private handleError(error: Response) {
        // just logging to the console for now...
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }   
}

現在在一個組件中,我希望同時運行(或鏈接) getUserInfo()getUserPhotos(myId)方法。 在 AngularJS 中,這很容易,因為在我的控制器中,我會做這樣的事情來避免“末日金字塔”......

// Good old AngularJS 1.*
UserData.getUserInfo().then(function(resp) {
    return UserData.getUserPhotos(resp.UserId);
}).then(function (resp) {
    // do more stuff...
}); 

現在,我已經嘗試在做我的組件類似的東西(更換.then對於.subscribe ),但是我的錯誤控制台要瘋了!

@Component({
    selector: 'profile',
    template: require('app/components/profile/profile.html'),
    providers: [],
    directives: [],
    pipes: []
})
export class Profile implements OnInit {

    userPhotos: any;
    userInfo: any;

    // UserData is my service
    constructor(private userData: UserData) {
    }

    ngOnInit() {

        // I need to pass my own ID here...
        this.userData.getUserPhotos('123456') // ToDo: Get this from parent or UserData Service
            .subscribe(
            (data) => {
                this.userPhotos = data;
            }
        ).getUserInfo().subscribe(
            (data) => {
                this.userInfo = data;
            });
    }

}

我顯然做錯了什么……我如何最好地使用 Observables 和 RxJS? 對不起,如果我問愚蠢的問題......但提前感謝您的幫助! 我還注意到在聲明我的 http 標頭時我的函數中的重復代碼......

對於您的用例,我認為flatMap運算符是您所需要的:

this.userData.getUserPhotos('123456').flatMap(data => {
  this.userPhotos = data;
  return this.userData.getUserInfo();
}).subscribe(data => {
  this.userInfo = data;
});

這樣,您將在收到第一個請求后執行第二個請求。 當您想使用前一個請求(前一個事件)的結果執行另一個請求時, flatMap運算符特別有用。 不要忘記導入操作符才能使用它:

import 'rxjs/add/operator/flatMap';

這個答案可以為您提供更多詳細信息:

如果你只想使用subscribe方法,你可以使用類似的東西:

this.userData.getUserPhotos('123456')
    .subscribe(
      (data) => {
        this.userPhotos = data;

        this.userData.getUserInfo().subscribe(
          (data) => {
            this.userInfo = data;
          });
      });

最后,如果您想並行執行兩個請求並在所有結果都得到通知時收到通知,您應該考慮使用Observable.forkJoin (您需要添加import 'rxjs/add/observable/forkJoin' ):

Observable.forkJoin([
  this.userData.getUserPhotos(),
  this.userData.getUserInfo()]).subscribe(t=> {
    var firstResult = t[0];
    var secondResult = t[1];
});

你真正需要的是switchMap操作符。 它獲取初始數據流(用戶信息),並在完成后將其替換為可觀察的圖像。

以下是我對您的流程的理解:

  • 獲取用戶信息
  • 從該信息中獲取用戶 ID
  • 使用用戶 ID 獲取用戶照片

這是一個演示 注意:我模擬了該服務,但代碼將適用於真正的服務。

  ngOnInit() {
    this.getPhotos().subscribe();
  }

  getUserInfo() {
    return this.userData.getUserInfo().pipe(
      tap(data => {
        this.userInfo = data;
      }))
  }
  getPhotos() {
    return this.getUserInfo().pipe(
      switchMap(data => {
        return this.userData.getUserPhotos(data.UserId).pipe(
          tap(data => {
            this.userPhotos = data;
          })
        );
      })
    );
  }

暫無
暫無

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

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