2017-03-06 9 views
1

私は、ユーザーに属するすべての "エクササイズ"を表示しようとしています。 「エクササイズ」オブジェクトは複数のユーザに属することができるので、これは典型的な多対多の関係です。ドキュメントがデータベースの構造を平坦化することを提案しているので、各ユーザは{ $exercise_key: true }という辞書を持っています。キーのリストからObservableListを作成する方法は?

検索の時間が過ぎると、ついにはうまくいきましたが、醜いですし、かなり遅くて非効率的です。私はまず、ユーザーからの運動キーの観測可能なリストを取得し、それらのキーのそれぞれに対して、私は 'メタデータ'属性として添付するFirebaseObservableObjectを取得します。

ページをロードすると、まず空の箇条書きの一覧が表示され、箇条書きの半分だけがテキストを取得し、最後は残りの部分が取得されます。すべてが表示されるまで〜2秒かかります。この「フリッカー」は、ページをリロードすることなく、新しいエクササイズを動的に追加した場合でも発生します。 https://papa-bear-1f486.firebaseapp.com(google authを使用)で試してみてください。

私のデータベースは次のようになります。

{ 
    "exercises" : { 
    "-KeVLI3UbGkRbifLffMa" : { 
     "createdAt" : 1488748884471, 
     "name" : "squat1" 
    }, 
    "-KeVLISTWaXbFxS6yqfv" : { 
     "createdAt" : 1488748886066, 
     "name" : "squat2" 
    }, 
    }, 
    "users" : { 
    "JtLTkOb8EXTeCeasF6vLpIpoUDB2" : { 
     "exercises" : { 
     "-KeVLI3UbGkRbifLffMa" : true, 
     "-KeVLISTWaXbFxS6yqfv" : true, 
     } 
    } 
    } 
} 

これは私が思い付いた醜いコードです:

private exercisesKey$: FirebaseListObservable<any[]>; 
private exercises$: Observable<any[]>; 

constructor(private af: AngularFire, private auth: AuthService) { 
    const path = '/users/' + auth.id + '/exercises'; 

    this.exercisesKey$ = af.database.list(path); 
    this.exercises$ = this.exercisesKey$.map((items) => { 
    items.map(item => { 
     item.metadata = this.getExercise(item.$key); 
     return item; 
    }); 
    return items; 
}); 

getExercise(key: string): FirebaseObjectObservable<IExercise> { 
    return this.af.database.object('/exercises/' + key); 
} 

そして、私の意見で:

<ul> 
    <li *ngFor="let exercise of exerciseService.exercises$ | async"> 
    {{ (exercise.metadata | async)?.name }} 
    </li> 
</ul> 

だから私は私の推測質問は:キーのリストから作成されたオブジェクトの観察可能なリストを取得する方法は?

package.json:

"angularfire2": "^2.0.0-beta.5", 
"firebase": "^3.5.2", 
+0

使用しているバージョン以降に多数のバグ修正があったため、AngularFire2の依存関係を更新することを検討する必要があります。 – cartant

+0

cartantのコメントに加えて、ngFor式と補間値の両方で非同期パイプを使用する必要はありません。私の理解は、あなたはこの場合、ngFor式でのみそれを使用するということです。 –

答えて

0

あなたは(あなたがすべての運動を取得する単一のクエリを実行する場合を除き)各運動のためのクエリを避けるためにできることは何もありません。しかし、あなたは少し物事を単純化することができます。

あなたは演習の観測可能に構成するためにcombineLatestを使用することができます。

import 'rxjs/add/observable/combineLatest'; 
import 'rxjs/add/observable/of'; 
import 'rxjs/add/operator/switchMap'; 

constructor(private af: AngularFire, private auth: AuthService) { 
    const path = '/users/' + auth.id + '/exercises'; 
    this.exercisesKey$ = af.database.list(path); 
    this.exercises$ = this.exercisesKey$ 
    .switchMap((items) => items.length === 0 ? 
     Observable.of([]) : 
     Observable.combineLatest(...items.map(item => this.getExercise(item.$key))); 
    ); 
}); 

運動キーの変更や運動そのものが変わる場合は、リスト、観測可能な構成は、演習のリストを再放出する場合。あなたが演習のスナップショットのみをしたいと、観察をしたくない場合は

その再放出運動の変化は、観測可能な各エクササイズ完了するために、代わりにcombineLatestforkJoinを使用してfirstを使用している場合:

import 'rxjs/add/observable/forkJoin'; 
import 'rxjs/add/observable/of'; 
import 'rxjs/add/operator/first'; 
import 'rxjs/add/operator/switchMap'; 

constructor(private af: AngularFire, private auth: AuthService) { 
    const path = '/users/' + auth.id + '/exercises'; 
    this.exercisesKey$ = af.database.list(path); 
    this.exercises$ = this.exercisesKey$ 
    .switchMap((items) => items.length === 0 ? 
     Observable.of([]) : 
     Observable.forkJoin(...items.map(item => this.getExercise(item.$key).first())); 
    ); 
}); 

をどちらの場合も、テンプレートは次のようになります:

<ul> 
    <li *ngFor="let exercise of exerciseService.exercises$ | async"> 
    {{ exercise.name }} 
    </li> 
</ul> 
+0

おかげさまで、非常に助かりました! – user1607256

関連する問題