0
   return this.usersTableService.fetchRequestedPageUsersIds(request).pipe(
        switchMap((idsToFetch) => {
          requestedIds = idsToFetch;
          return [this.usersTableService.getNewIdsToFetch(requestedIds, entities), of(idsToFetch)];
        }),
        //.......?(([newIds, idsToFetch]) => {
          return this._fetchNewUsersFromAPI(requestedIds, request, newIds, entities);
        }),
        catchError((err) => of(loadPageFail(err)))
      );

what operator should I use in order to get the value of the return tuple before ?

Kaki6876
  • 77
  • 1
  • 6

2 Answers2

2

You can use forkJoin for this

 return this.usersTableService.fetchRequestedPageUsersIds(request).pipe(
        switchMap((idsToFetch) => {
          return forkJoin([this.usersTableService.getNewIdsToFetch(requestedIds, entities), of(idsToFetch)]);
        }),
        mergeMap(([newIds, idsToFetch]) => {
          return this._fetchNewUsersFromAPI(requestedIds, request, newIds, entities);
        }),
        catchError((err) => of(loadPageFail(err)))
      )
Ajantha Bandara
  • 1,473
  • 15
  • 36
1

You would normally use the map operator(https://stackblitz.com/edit/so-tuple-map?file=index.ts):

const obs$ = of(1).pipe(map(y => ['abc', 'def']), map(([str1, str2]) => str1 + str2))

But if you try that you will encounter other issues with your code ie:

  • its not good practice to store a local variable inside a switchMap then return it using of
  • _fetchNewUsersFromAPI needs to be inside a switchMap

Ultimately you'll still be faced with the fundamental problem of how to pass parameters down the observable chain, which I suspect is how you've ended up in this situation to begin with.

There is currently a bountied question asking about the same problem here: How to pass results between chained observables

IMO the best solution from that question is to use nested pipes ie:

const newUsers$ = requestsSubject.pipe(
  switchMap(request =>
    this.usersTableService.fetchRequestedPageUsersIds(request).pipe(
      switchMap(idsToFetch =>
        this.usersTableService.getNewIdsToFetch(idsToFetch).pipe(
          switchMap(newIds =>
            this._fetchNewUsersFromAPI(idsToFetch, request, newIds, entities)
          )
        )
      )
    )
  )
);

An alternative way using await and toPromise:

function getUsers(request){
  const idsToFetch = await this.usersTableService.fetchRequestedPageUsersIds(request).toPromise();
  const newIds = await this.usersTableService.getNewIdsToFetch(idsToFetch, entities).toPromise();
  const newUsers = await this._fetchNewUsersFromAPI(idsToFetch, request, newIds, entities).toPromise();
  
  return newUsers;
}
wlf
  • 3,086
  • 1
  • 19
  • 29
  • 1
    OP asks for help with an RxJs question and you say use a promise. – Adrian Brand Aug 17 '20 at 23:07
  • 1
    OP is lost in RxJs when await/promises will solve it in a simple way. Go read the answers to the bountied question I've linked where I've left a non promise answer, but I still think promise is the best way. BTW I've answered his question anyway - use the map operator. – wlf Aug 17 '20 at 23:13
  • You just prefer an different paradigm. You can easily solve this task 100% reactive and also make the request itself an event. Then no getUsers would have to be called, instead a requestUser$$.next(...) starts the pipe. I agree promises is one way to solve this, but it's not the easiest or the one with more advantages in the future. It might be the one non reactive paradigm programmer understand the easiest. – Jonathan Stellwag Aug 18 '20 at 06:54
  • Taking into account the comments above, I have now provided a nested pipes solution which is pure RxJS. – wlf Aug 18 '20 at 11:08