This issue has popped up a couple of times, and every time it does I scramble to figure out how to do it the right way, since I can never seem how to find how I did it last time when I need it.
This time it came up because I realized I need to do an extra httpGet
call when processing a previous httpGet
call:
http.getWrapper<T>(whatever)
.pipe<T, T>(map<T, T>(res => getWrapper2<T, T>(res)) // New function, returns the same type it was given
.pipe<T, U>(oldStuff)
The issue that I'm having is that previously, without the extra get
call, my oldStuff
handler received a T
that it could handle without issue. But the new get
call returns an Observable<T>
, and I always find it confusing to figure out how to tell the pipe chain to wait for the get
to finish, and use the final value. Anything I can think of doing, which mostly seems to be variations of toPromise()
and async/await
, just move the extra layer between me and my data around, and I can't quite seem to get to it. For some reason inserting this second get
just always seems to be more confusing than the first get
was, and I don't know if I need a structure change or it's just my thinking is off.
To make things even more confusing, the extra layer of processing is only sometimes needed:
.pipe(map(res => condition(res) ? getWrapper2(res) : res))
What can I do to await and flatten this so I can pass the new get
result to the rest of the pipe
chain?
CodePudding user response:
you are looking for high order observables
the most popular operators:
mergeMap
, switchMap
, concatMap
These operators should return observable and in the next step you will receive data
import { of } from 'rxjs';
import { map, mergeMap } from 'rxjs/operators';
const initialApiCall = () => of('initialApiCall');
const extraApiCall = (res) => of(res '_' 'extra result'); // getWrapper2
const condition = (res) => !res;
initialApiCall()
.pipe(
mergeMap((res) => (condition(res) // checking condition
? extraApiCall(res) // api call
: of(res)) // should convert privitive data to observable
),
map((data) => console.log(data)) // here you will have result of `extraApiCall` or `res`
)
.subscribe();
DEMO:
https://stackblitz.com/edit/rxjs-suryq3?file=index.ts
CodePudding user response:
url_users = 'https://jsonplaceholder.typicode.com/users';
url_posts = 'https://jsonplaceholder.typicode.com/posts';
this.http
.get(this.url_users)
.pipe(
tap((res) => console.log('users- ', res)),
concatMap((users) => this.http.get(this.url_posts '/' users[3].id))
)
.subscribe({
next: (posts) => {
console.log(posts);
},
error: (err) => console.log(err),
});
- concatMap subscribes to the inner Observable (In our case 2nd
http.get
) and sends its output to the result Observable- concatMap will wait for previous HTTP Observable to complete before mapping the new value to an HTTP Observable, subscribing to it and
therefore triggering the next get
you will find more about Higher-Order RxJs Mapping Operators: switchMap, mergeMap, concatMap (and exhaustMap)