TypeScriptを使用してAngular2のhttpデータからRxJS Observableをチェーンする


95

私は現在、AngularJS 1. *で過去4年間楽しく働いた後、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ヘッダーを宣言するときに、関数内のコードが繰り返されていることに気付きました...

回答:


137

あなたのユースケースでは、flatMap演算子はあなたが必要とするものだと思います:

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

このようにして、最初の要求を受け取ったら、2番目の要求を実行します。この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];
});

ただし、「TypeError:source.subscribe is not a function in [null]」というエラーが表示されます
Mike Sav

このエラーはどこにありますか?呼び出すときthis.userData.getUserInfo()
ティエリーテンプリエ2016

3
ああ!私の答えにはタイプミスがありました:のthis.userData.getUserPhotos(), this.userData.getUserInfo()代わりにthis.userData.getUserPhotos, this.userData.getUserInfo()。ごめんなさい!
ティエリーテンプリエ2016

1
なぜflatMapなのですか?なぜswitchMapではないのですか?私は、最初のGET要求が突然、ユーザーのために別の値を出力した場合、あなたは、ユーザーの以前の値のための画像を取得しておくのは嫌だと仮定します
f.khantsis

4
これを見て、なぜ機能しないのか疑問に思う方のために:RxJS 6では、インポートとforkJoinの構文がわずかに変更されました。import { forkJoin } from 'rxjs';次に、関数をインポートするために追加する必要があります。また、forkJoinはもはやObservableのメンバーではなく、別個の関数です。だからObservable.forkJoin()それの代わりにただforkJoin()です。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.