web-dev-qa-db-ja.com

Angular2でネストされたObservable呼び出しを行う方法

ネストされたObservable呼び出しを行うときに問題が発生します。つまり、ユーザーを取得し、ユーザーからIDを取得して別のHTTP呼び出しを行い、最終的に結果を画面に表示するHTTPサービスの呼び出しを意味します。

1)HTTP GET 1:ユーザーを取得します

2)HTTP GET 2:一意の識別子をパラメーターとして渡してユーザーの設定を取得する

これは、コンポーネント_Blah.ts_の次のコードに変換されます。

バージョン1-このコードは何も表示しません

_ ngOnInit() {
        this.userService.getUser()
            .flatMap(u => {
                this.user = u; // save the user
                return Observable.of(u); // pass on the Observable
            })
            .flatMap(u => this.userService.getPreferences(this.user.username)) // get the preferences for this user
            .map(p => {
                this.preferences = p; // save the preferences
            });
    }
_

バージョン2-このコードは機能しますが、私にとって間違ったアプローチのようです:

_ this.userService.getUser().subscribe(u => {
            this.user = u;
            this.userService.getPreferences(this.user.username).subscribe(prefs => {
                this.preferences = prefs;
            });
        });
_

そして、これがテンプレートです:

_<h3>User</h3>

<div class="row col-md-12">
    <div class="col-md-6">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">User details</h3>
            </div>
            <div class="panel-body">
                <table class="table table-condensed">
                    <thead>
                        <tr>
                            <th>Username</th>
                            <th>Full Name</th>
                            <th>Enabled</th>                                
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>{{user?.username}}</td>
                            <td>{{user?.fullName}}</td>
                            <td>{{user?.enabled}}</td>                          
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <!-- end of col 1-->

    <div class="col-md-6">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">User preferences</h3>
            </div>
            <div class="panel-body">
                <table class="table table-condensed">
                    <thead>
                        <tr>
                            <th>Language</th>
                            <th>Locale</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>{{preferences?.preferences?.get('language')}}</td>
                            <td>{{preferences?.preferences?.get('locale')}}</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <!-- end of col 2-->

</div>
<!-- end of row 1-->
_

http get()呼び出しを次のように単純に行うサービスを表示することに意味はないと思います。

_  http.get('http://blablah/users/')
        .map((response) => response.json())
_

オブザーバブルのチェーンを定義するのに最適なアプローチを提案してください。

23
nuvio

Rxjsの演算子を少し読んでください。あなたの例は非常に冗長であり、flatMapmapを使用するはずのない方法で使用しています。また、Observableにサブスクライブしていないため、最初の例は機能しません。

これは必要なことを行います:

ngOnInit() {
    this.userService.getUser()
        .do(u => this.user = u) //.do just invokes the function. does not manipulate the stream, return value is ignored.
        .flatMap(u => this.userService.getPreferences(u.username))
        .subscribe(p => this.preferences = p);
}

Rxjs 5.5以降では、 パイプ可能な演算子 を使用する必要があります。

ngOnInit() {
    this.userService.getUser().pipe(
        tap(u => this.user = u),
        flatMap(u => this.userService.getPreferences(u.username))
      ).subscribe(p => this.preferences = p);
}
33
j2L4e

申し分なく、インターネットからの情報を苦労してまとめた1日の後、ここでObservableのチェーン(順番にObservableを呼び出す-次々に)について学んだことがあります。

私はAngular2(4)Webサイトで作業しており、このサイトはJavaバックエンドAPIを使用してデータベース内の情報を取得/設定/変更します。

私の問題は、Observables(RxJS)を返すシーケンスで2つのAPI(HTTP POST)呼び出しを行わなければならなかったことです。

Operation1とOperation2があります。操作2操作1の完了後に実行する必要があります。 enter image description here

Variant1->最初は、他の内部でそれを行いました(javascriptのネストされた関数のように):

     this.someService.operation1(someParameters).subscribe(
        resFromOp1 => {
          this.someService.operation2(otherParameters).subscribe(
            resFromOp2 => {
              // After the two operations are done with success
              this.refreshPageMyFunction() 
            },
            errFromOp2 => {
              console.log(errFromOp2);
            }
          );
        },
        errFromOp1 => {
          console.log(errFromOp1);
        }
      );

このコードは合法で動作していますが、Promisesで非同期関数を使用する方法のように、これらのObservableを次々とチェーンする必要がありました。 1つの方法は、ObservablesをPromiseに変換することです。

別の方法は、RxJS flatMapを使用することです。

Variant2->別の方法は、flatMapでこれを行うことです。

   this.someService.operation1(someParameters)
    .flatMap(u => this.someService.operation2(otherParameters))
    .subscribe(function(){
        return this.refreshPageMyFunction()
      },
      function (error) {
        console.log(error);
      }
    );

Variant3-> Arrow関数と同じ:

   this.someService.operation1(someParameters)
    .flatMap(() => this.someService.operation2(otherParameters))
    .subscribe(() => this.refreshPageMyFunction(),
      error => console.log(error)
    );

Observablesを返すメソッドは、基本的に次のとおりです。

  operation1(someParameters): Observable<any> {
    return this.http.post('api/foo/bar', someParameters);
  }

  operation2(otherParameters): Observable<any> {
    return this.http.post('api/some/thing', otherParameters);
  }

追加のリソースと役立つコメント:

This post approved answer by @j2L4e: https://stackoverflow.com/a/40803745/2979938

https://stackoverflow.com/a/34523396/2979938

https://stackoverflow.com/a/37777382/2979938
7
Combine

あなたが正しい、ネストされたサブスクライブが間違っている...

フラットマップが正しい

これは役立つはずです

https://embed.plnkr.co/mqR9jE/preview

またはこのチュートリアルを読む

https://Gist.github.com/staltz/868e7e9bc2a7b8c1f754

いくつかのコード...

// responseStream: stream of JSON responses
var responseStream = requestStream
  // We use flatMap instead of map to prevent this stream being a metastream - i.e. stream of streams
  .flatMap(requestUrl => {
    // Convert promise to stream
    return Rx.Observable.fromPromise($.getJSON(requestUrl));
  }).publish().refCount(); // Make responseStream a hot observable, prevents multiple API requests
// see https://Gist.github.com/staltz/868e7e9bc2a7b8c1f754#gistcomment-1255116

ここでのリクエストURLは、別のストリーム/ Observableから発行された入力です。

responseStreamをサブスクライブします

2
danday74

バージョン1が最適であり、機能するはずです。購読するのを忘れただけです:

 ngOnInit() {
    this.userService.getUser()
        .flatMap(u => {
            this.user = u; // save the user
            return Observable.of(u); // pass on the Observable
        })
        .flatMap(u => this.userService.getPreferences(this.user.username)) // get the preferences for this user
        .map(p => {
            this.preferences = p; // save the preferences
        })
        .subscribe();
}
2
soywod