2016-07-05 11 views
0

私は、オブジェクト(ユーザ)の集合を得るためにhttpを呼び出すコンポーネントを持っています。それらのユーザーのそれぞれについて、別のHTTPコールをもう一度行って、ユーザーの追加の詳細を取得する必要があります。 RxJSとobservablesでこれをどうやって行うのですか?私たちがgithubユーザーのリストを取得し、フォロワー数を取得するために各フォロワーを取得しようとするこのplunkに示された動作。Angular2 RxJSストリーム親コレクションの各子にHTTPを呼び出す

サブスクリプションコードは、user-grid.component.tsにあります。

http://plnkr.co/edit/Xuu5jqeKVmbY5qwHLJJt

ngOnInit(){ 
    this.users$ = this._githubUserService.getUsers() 
     .map((res) => res.json()) 
     .flatMap((users) => Observable.from(users)) 
     .flatMap((e) => { 
      return this._githubUserService.getFollowers(e.followers_url) 
      .map((followers)=> followers.json()) 
     }, (e, res) => e.followers = res)  
} 
+0

あなたはあなたの第二 'flatMap'で' return'が欠けているように見えます。 – paulpdaniels

+0

エラーを解決したが、正しい出力を得られない戻り値を修正しました –

答えて

1

私は非同期パイプに深く慣れていませんが、あなたの問題は*ngForがリストの再水和としてObservableの新しい値をそれぞれ扱うということです。 flatMapに渡している2番目の関数は、フォロワー呼び出しから返された配列を返しています(新しい要求によって解決されるたびにリストが再構築されるため、ちらつきの原因となります)。

toArray演算子を最後に追加すると、すべての値が返されるまで待つことになります。

さらに、followersを配列に変換するので、ネストされたh4で非同期パイプを使用する必要はありません。

はこちらをご覧ください:

http://plnkr.co/edit/X2OjHGiPpmml2cmLD1tm?p=preview

興味深いビット:

import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/mergeMap'; 
import 'rxjs/add/operator/toArray'; 


ngOnInit(){ 
    this.users$ = this._githubUserService.getUsers() 
     .map((res) => res.json()) 
     .flatMap(users => users) 
     .flatMap(
      (e) => this._githubUserService.getFollowers(e.followers_url), 
      (e, res) => Object.assign(e, {followers: res.json()})) 
     .toArray(); 
} 

// in user-grid.component.html 
<md-list> 
    <h1 md-header>GitHub Users</h1> 
    <md-list-item *ngFor="let user of users$ | async"> 
    <a href="https://github.com/{{user.login}}" target="_new"> 
     <img md-list-avatar [src]="user.avatar_url"> 
    </a> 
    <h4>{{user.login}} (followers: {{user.followers.length}})</h4> 
    </md-list-item> 
</md-list> 
+0

私は、.flatMap(users => users)が私たちにとって何をしているのかはっきりしていませんか?それはコレクションを取り、コレクションの各アイテムがノードである単一のオブジェクトに変換しますか?なぜこれが第2フラットマップの前で必要なのか不思議です。このソリューションは動作し、非常に読みやすい、ありがとう! –

+1

正確に。 'flatMap'はusers配列を平坦化します。それがなければ、2番目のフラットマップは個々のユーザーの代わりにユーザーの配列を受け取るでしょう。通常は 'Observable'を平坦化することになりますが、' Arrays'や 'Promises'のような繰り返し可能な型を暗黙的に扱うことができます。 – paulpdaniels

0

私は(それは私に403を返します - 禁断の)あなたのplnkrを開くことができないんだけど、私はあなたがこのような構造を構築したい場合だと思います:

[{ userId: 1, followersQtt : 25 }, { userId: 2, followersQtt : 18 }, ... ]

あなたはこのような何かを行うことができます:

//get the users' json as an Array 
let usersJsonArray = this._githubUserService.getUsers().map((res) => res.json()); 

this.users$ = Observable.from(usersJsonArray) //we have to convert the Array to an Observable    
       .flatMap((user) => { 

        //get the followers' json 
        let followersJsonArray = this._githubUserService.getFollowers(user.followers_url).map((res) => res.json()); 

        return Observable.from(followersJsonArray) //again, we have to convert the Array to an Observable        
           .map(() => 1) //map each follower to the number 1 
           .reduce((x,y) => x+y) //sums up all the followers (that were mapped to the number '1') 
           .map((followersQtt) => { userId : user.id, followersQtt : followersQtt }) //return an object with the informations (I don't know if the user's id is really in the property user.id)  

       }); 
+0

.map((users)=> Observable.from(users))ここでフラットマップを使用する必要がありますか? – maxisam

+0

現時点では、私はそれが 'Observable'ではなく' Array'であると期待しているので、 'flatMap'関数は存在しません。しかし、今考えていることは、問題であるかもしれない、我々はArray Observable ..へ私の答えを更新しています – demarchisd

関連する問題