Reputation: 752
I'm trying to use AngularFire2. I am querying and everything works fine below.
I want to combine all/most of the observables into one:
getTournamentWithRounds(key):Observable<Tournament> {
return this.af.database
.object(`/tournaments/${key}`)
.map(tourney => {
let t = Tournament.fromJson(tourney);
this.af.database.list('players', {
query: {
orderByChild: 'tournament_key',
equalTo: key
}
})
.map(Player.fromJsonList)
.subscribe(ps => { t.players = ps; });
this.af.database.list('rounds', {
query: {
orderByChild: 'tournament_key',
equalTo: key
}
})
.map(Round.fromJsonList)
.subscribe(rs => { t.rounds= rs; })
return t;
})
}
I was wondering if I could join all the observables and get the output with a single subscribe function.
I would like to know when all the initial data has been loaded and perform additional computation in the controller before outputting it to the view.
Also, how could this be extended to include the matches for each round?
My extension to the above code would be:
...
this.af.database.list('rounds', {
query: {
orderByChild: 'tournament_key',
equalTo: key
}
})
.map(rounds => {
return rounds.map((round) => {
let r = Round.fromJson(round);
this.af.database.list('matches', {
query: {
orderByChild: 'round_key',
equalTo: round.$key
}
})
.map(Match.fromJsonList)
.subscribe(matches => { r.matches = matches; })
return r;
})
})
.subscribe(rs => { t.rounds= rs; })
...
Upvotes: 2
Views: 649
Reputation: 58440
You could use the combineLatest
operator to combine the players and rounds with the tournament:
getTournamentWithRounds(key): Observable<Tournament> {
return this.af.database
.object(`/tournaments/${key}`)
.combineLatest(
this.af.database.list('players', {
query: {
orderByChild:'tournament_key',
equalTo: key
}
}),
this.af.database.list('rounds', {
query: {
orderByChild:'tournament_key',
equalTo: key
}
})
)
.map(([tourney, players, rounds]) => {
let t = Tournament.fromJson(tourney);
t.players = Player.fromJsonList(players);
t.rounds = Round.fromJsonList(rounds);
return t;
});
}
Whenever any of the observables emits, the latest values will be re-combined and a new Tournament
will be emitted.
Extending this to include each round's matches is a little more complicated, as each round's key is needed for the matches query.
The emitted rounds can be mapped to an array of list observables for the matches and forkJoin
can be used to join the observables, with the forkJoin
selector function being used to combine the matches with the rounds. switchMap
is then used to emit the rounds.
getTournamentWithRounds(key): Observable<Tournament> {
return this.af.database
.object(`/tournaments/${key}`)
.combineLatest(
this.af.database.list('players', {
query: {
orderByChild:'tournament_key',
equalTo: key
}
}),
this.af.database.list('rounds', {
query: {
orderByChild:'tournament_key',
equalTo: key
}
})
.switchMap(rounds => {
Observable.forkJoin(
rounds.map(round => this.af.database.list('matches', {
query: {
orderByChild: 'round_key',
equalTo: round.$key
}
}).first()),
(...lists) => rounds.map((round, index) => {
let r = Round.fromJson(round);
r.matches = Match.fromJsonList(lists[index]);
return r;
})
)
})
)
.map(([tourney, players, rounds]) => {
let t = Tournament.fromJson(tourney);
t.players = Player.fromJsonList(players);
t.rounds = rounds;
return t;
});
}
Upvotes: 5