I am trying to get my head around Observables in RxJs. I have a page where I need to display all users for a specific site. User and SiteUser entities are in separate API endpoints. I have the following endpoints
userService.getSiteUsers(siteId: string): Observable<SiteUser[]>;
where
export class SiteUser {
site_id: string;
user_id: string;
}
and
userService.getUser(user_id: string): Observable<User>;
where
export class User {
id: string;
name: string;
email: string;
....
}
So I have to do the following:
I can easily do this
let users: User[] = []; // this is bound in html view to a table
this.userService.getSiteUsers("my site id")
.subscribe((siteUsers) => {
for (let siteUser of siteUsers) {
this.userService.getUser(siteUser.user_id)
.subscribe((user) => {
users.push(user);
});
}
});
But this approach feels dirty or cumbersome. I am sure there is a much cleaner Observable way of doing it. I am very new to Observables, but as far as I understand I should be able to do something like this (not selectMany and mergeAll function are just my guesses, I tried it and it didn't work, I couldn't even find selectMany in rxjs library))
Get site user observable array -> for each element in observable array create user observable -> merge them all into observable array of users -> subscribe, so something like this:
this.userService.getSiteUsers("my site id")
.selectMany((siteUser) => this.userService.getUser(user))
.mergeAll()
.subscribe((users) => {
this.users = users;
});
Can someone please help, I can't get it working
EDIT------
Maybe something like this
this.userService.getSiteUsers("my site id")
.switchMap(
(siteUsers) => {
let userQueries: Observable<User>[] = [];
for (let siteUser of siteUsers) {
userQueries.push(this.userService.getUser(siteUser.user_id));
}
return Observable.forkJoin(userQueries);
}
)
.subscribe((users) => {
this.users = users;
});
You should use the .flatMap()
/ .mergeMap()
operator if one http call depends on another http call.
For example in your case something like this would do,
this.userService.getSiteUsers("my site id")
.switchMap(
(siteUsers) => {
let userQueries: Observable<User>[] = [];
for (let siteUser of siteUsers) {
userQueries.push(this.userService.getUser(siteUser.user_id));
}
return Observable.forkJoin(userQueries);
}
)
.subscribe((users) => {
this.users = users;
});
Try something like this:
this.userService.getSiteUsers("my site id")
.flatMap((siteUsers) => {
// map every user into an array of observable requests
const usersObservables = siteUsers.map(siteUser => this.userService.getUser(siteUser.user_id)).map((res:Response) => res.json())
return Observable.forkJoin(...usersObservables)
}).subscribe(users => {
//you have all your users now;
console.log(users)
});
We use the spread operator in here:
return Observable.forkJoin(...usersObservables)
So we transform our array into arguments, like this:
return Observable.forkJoin(observableUser1, observableUser2, observableUser...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With