ネストされた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())
_
オブザーバブルのチェーンを定義するのに最適なアプローチを提案してください。
Rxjsの演算子を少し読んでください。あなたの例は非常に冗長であり、flatMap
とmap
を使用するはずのない方法で使用しています。また、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);
}
申し分なく、インターネットからの情報を苦労してまとめた1日の後、ここでObservableのチェーン(順番にObservableを呼び出す-次々に)について学んだことがあります。
私はAngular2(4)Webサイトで作業しており、このサイトはJavaバックエンドAPIを使用してデータベース内の情報を取得/設定/変更します。
私の問題は、Observables(RxJS)を返すシーケンスで2つのAPI(HTTP POST)呼び出しを行わなければならなかったことです。
Operation1とOperation2があります。操作2操作1の完了後に実行する必要があります。
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
あなたが正しい、ネストされたサブスクライブが間違っている...
フラットマップが正しい
これは役立つはずです
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をサブスクライブします
バージョン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();
}