2017-02-17 14 views
5

私はアプリケーション内で基本的な変化の検出に多くの苦労をしています。私は数日間このことをして意志を失ってしまった!ここの誰かが私に正しい方向を向けることができるのだろうかと思います。rxjs combineLatestとAnguar2は観測可能なアレイで検出を変更します

groupには2 userのリストがあります。 1つはmembers、もう1つはmoderatorsです。

このメソッドは、データベースに接続して、それぞれ$key値のオブジェクトのリストを取得します。ここでは、これらのキーを使用して各ユーザーの実際のUserDataを取得します。私はすべてを試して、combineLatestが私が働くように思える唯一のものです。

したがって、両方とも関数を呼び出すと、テンプレートにasyncパイプを使用しています。

members$ = myService.getMemberListByType("blah", "members"); 
moderators$ = myService.getMemberListByType("blah", "moderators"); 

私の機能は次のようになります。

private getMemberListByType(groupKey: string, memberType: string) { 

    return this.af.database.list(`groups/${groupKey}/${memberType}`) 
     .switchMap(userListKeyMap => { 

     console.log("UserListKeyMap", memberType, userListKeyMap); 

     let usersObservables: Observable<UserData>[] = []; 
     userListKeyMap.forEach((object) => { 
      usersObservables.push(this.af.database.object(`users/${object.$key}`) 
      .map(UserData.fromJSON)); 
     }); 

     return Observable.combineLatest(usersObservables); 
     }); 

    } 

ただし、このリストの変更は次のように検出されません。他の場所の別の方法でmemberが削除され、moderatorに追加されたとします。この場合、リストmembersは空のユーザーリスト[]を発行しています。

My * ngIfと* ngForは、この新しい空のオブジェクトの変更を検出しません。その結果、(テンプレート上の)ユーザーは2つのリストの一部になりましたが、その下のデータはログによって強調されて完全に正確です。

私は、空の配列に結合すると、これが私の問題の原因だと感じます。何も放出することはできません....どのように角度の変化がありますか?私はそれを解決する方法を知らない。この「空の」ユースケースにcombineLatestの代替手段がありますか?私はasyncパイプを使用しているので、意味があることが必要です。

誰かが私の問題を明るく照らすことができますか?

ありがとうございました!

更新

私はこの問題は、angular2が空の観察可能なリストを検出しないとです確信しています。 Observable Arrayに値があるが、後でその値が空になる場合Angular2は空の配列を表示しません。私はこの時点でこの問題を解決する方法がありません。私のアプローチが間違っているか、空の観測可能リストを登録するために何か具体的なことが起こる必要がありますか?

screen of problem

  1. 青=コンポーネントの負荷状態が良好で、ユーザがメンバーでした。
  2. 緑色=ユーザーはメンバーから管理者/モデレーターに移動しました。
  3. 赤=これは存在しないので、なぜまだ表示されていますか?

    private getMemberListByType(groupKey: string, memberType: string) { 
    
        return this.af.database.list(`groups/${groupKey}/${memberType}`) 
    
          // Force the source obs to complete to let .toArray() do its job. 
          .take(1) 
    
          // At this point, the obs emits a SINGLE array of ALL users. 
          .do(userList => console.log(userList)) 
    
          // This "flattens" the array of users and emits each user individually. 
          .mergeMap(val => val) 
    
          // At this point, the obs emits ONE user at a time. 
          .do(user => console.log(user)) 
    
          // Load the current user 
          .mergeMap(user => this.af.database.object(`users/${user.$key}`)) 
    
          // At this point, the obs emits ONE loaded user at a time. 
          .do(userData => console.log(userData)) 
    
          // Transform the raw user data into a User object. 
          .map(userData => User.fromJSON(userData)) 
    
          // Store all user objects into a SINGLE, final array. 
          .toArray(); 
    
    } 
    

    注:

+0

は、あなたがこの回答をhttp周りを見て持ってお勧め:// stackoverflowの.com/questions/41584409/change-detection-in-angular-2/41585545#41585545 – Aravind

+0

チームビューアでご利用いただけますか? – Aravind

答えて

4

のリストにforkJoinを使用してみてください:

private getMemberListByType(groupKey: string, memberType: string) { 

    return this.af.database.list(`groups/${groupKey}/${memberType}`) 
     .switchMap(userListKeyMap => { 

     console.log("UserListKeyMap", memberType, userListKeyMap); 

     let usersObservables: Observable<UserData>[] = []; 
     userListKeyMap.forEach((object) => { 
      usersObservables.push(this.af.database.object(`users/${object.$key}`) 
      .map(UserData.fromJSON)); 
     }); 

     return usersObservables.length > 0 ? Observable.combineLatest(usersObservables) : Observable.of([]); 
     }); 
} 
+0

ありがとう!それは動作するようです!混乱している人にとっては 'combineLatest([])'と空の配列が有効であるが、 'of([])'は値を出すのに対し、決して値を出さないことに注意してください。これは、テンプレートの検出を変更するための鍵です。私はそれを感謝Kemsky。 – Clark

+0

これは素晴らしい+1です、ありがとう! – dhndeveloper

2

あなたはこのような何かを試してみてください。do()で始まる行は、ここで何が起こっているのかを説明するためだけにあります。最終コードにそれらを保持する必要はありません。

+0

ありがとう!私は自分の不毛の試みが問題の核心になければならないことを知っていました。私はrxjsのドキュメントよりむしろ説明したチュートリアルシリーズが好きです。私が今抱えている唯一の問題は、私が応答を購読できないことです。私はあなたのトレースステートメントを見ていますが、奇妙なことに 'this.groupService.getGroupManagerList(groupKey).subscribe(成功=> console.log(成功))'は非常に奇妙なものです。 – Clark

+0

確かに非常に奇妙です。コンソールにログが表示されている場合は、オブザーバブルが実行されていることを意味します。あなたは正しい方法を購読していますか?あなたの初期コードは 'getMemberListByType()'と言っていて、今は 'getGroupManagerList()'と言っています。 – AngularChef

+0

ああ、混乱のために申し訳ありません!私はこのメソッドに直接アクセスしませんが、文字列型を隠すことができるように他のメソッドを返します。基本的には同じことです。私の 'async'パイプがそれに反応したり、上記のサブスクリプションに反応しないのは単なる奇妙なことです。それはエラーでもないし、購読しても定義されていないし、実行している 'do's'が表示されているのを見たことがある。 – Clark

4

あなたのアプローチは私にとって正しいようです。空の配列を持つcombineLatest()を使用すると、エラーで終わるべきではありません(たとえば、forkJoinと同様、空の配列を使用すると有効なユースケースです)。それで空の配列のために完了したとしても、switchMapを使用しているので、これは私が考えるべき問題ではないはずです。

私はので、私はthis.af.database.objectがちょうどを完了するか、それがあれば何をしたいおそらく私であるすべての変更(上の値を発し一度、その後、すべてのアイテムを発するかどうかわからないAngularFire2の経験を持っていません推測)。

はとにかくcombineLatest()またはforkJoin()を使用して、非常に一般的な問題は、そのソース観測は、常に少なくとも一つのアイテムを発する を持っているということです。つまり、this.af.database.objectのいずれかが空白の場合、combineLatest()は何も出力しません。

常に少なくとも1つの値がstartWith()であることを確認できます。

userListKeyMap.forEach((object) => { 
    usersObservables.push(this.af.database.object(`users/${object.$key}`) 
     .startWith('{}') 
     .map(UserData.fromJSON)); 
}); 

これはAngular2がそれにサブスクライブし、新しいアイテムが放出されても、サブスクリプションを保つことを確認するだけでObservable.timer()代わりthis.af.database.objectthis.af.database.listのを使ってみて問題が解決しない場合は、次のような例。

+0

私はここに私のコメントをリファクタリングしました。ありがとうございました!残念ながら、私はあなたの提案を働かせることはできませんでした。私は本当にその '.startWith'を使用したくありません。それを読んだことは素晴らしいことでした!ちょうどそこには何もなく、冗長と思われるようなふりをしています。 – Clark

1

簡単な回避策はあり観測

let userListKeyMap$ = Rx.Observable.of([{key:1}, {key:2}, {key:3}]); //mock keys 
 
let requestUserFromKey = (key) => Rx.Observable.of({user: key}).delay(1000); //mock users 
 

 
let result$ = userListKeyMap$.switchMap((userKeys) => 
 
Rx.Observable.forkJoin(userKeys.map(uk => requestUserFromKey(uk.key)))); 
 

 
result$.subscribe((users) => console.log('got some users: ', users));
<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>

+0

こんにちはカローラありがとう!私はこれを同じ文脈にマッサージすることができましたが、私は観察可能な創造が問題ではないと思います。あなたの提案でも、Angular2は空の配列を検出しません。 (上記の私の質問のスクリーンショットを参照してください)。 – Clark

関連する問題