简体   繁体   中英

combine multiple http calls in RxJS

i am a rxjs newbie.

I'm trying to combine several observables to get a list of data from a rest api and load into a ngx-datatable

following the server-side paging on ngx-datatable example I have defined a PageData object:

export class PagedData<T> {
  data = new Array<T>();
  page = new Page();
}

and I have a working setPage method in my component to retrive my users list:

setPage(pageInfo) {
    this.page.pageNumber = pageInfo.offset;
    this.pageObserver = this.userService.getPaged<User>(this.page).subscribe(pagedData => {
      this.page = pagedData.page;
      this.rows = pagedData.data;
    });
  }

now I have to improve this solution with some others logic. the User object from my rest server have this form:

{
        "createdAt": "2021-02-20T13:06:23.911Z",
        "firstname": "Roberto",
        "id": 7,
        "lastname": "Rossetti",
        "links": [
            {
                "saleforces": "/users/7/saleforces"
            }
        ],
        "name": "robertorossetti",
        "parent": null,
        "parentId": null,
        "updatedAt": "2021-02-20T13:06:23.933Z",
        "users": []
    }

so I need to follow the link "/users/7/saleforces" to retrieve the saleforces related to my user. and here I am stuck.

I tryed to implement a new observable that extends my working code in this manner, following the examples I found here

public getPagedWithSaleForce2(page: Page, queryParams?: QueryStringParameters, options?: HttpOptions): Observable<PagedData<User>> {
    return super.getPaged<User>(page, queryParams, options).pipe(
      switchMap((pagedData: PagedData<User>) => {
        if (pagedData.data.length > 0) {
          return forkJoin(
            pagedData.data.map((user: User) => {
              const saleForceEndpoint = _.find(user.links, 'saleforces');
              return this.getRaw<SaleForce>(saleForceEndpoint.saleforces).pipe(
                map((saleForce: SaleForce[]) => {
                  user.saleForces = saleForce;
                  return (user);
                })
              );
            })
          );
        } else {
          return of(null);
        }
      })
    );
  }

obviously this code doesn't work.

so, how I can fill my pageData.data with the array of users enriched by their saleForces? how I can call the saleForceEndpoint in parallel?

thanks in advance for the help

I found a solution splitting the problem in two:

in my controller:

# user-list.component.ts
setPage(pageInfo) {
    this.page.pageNumber = pageInfo.offset;
    this.pageObserver = this.userService.getPagedWithSaleForce(this.page).subscribe(pagedData => {
      this.page = pagedData.page;
      this.rows = pagedData.data;
    });
  }

in my service:

# user.service.ts
public getPagedWithSaleForce(page: Page, queryParams?: QueryStringParameters, options?: HttpOptions): Observable<PagedData<User>> {
    return super.getPaged<User>(page, queryParams, options)
      .pipe(
        mergeMap((pagedData: PagedData<User>) => {
          return this.followSaleforceLink(pagedData).pipe(
            map(users => {
              return {users, pagedData};
            })
        );
        }),
        map(({users, pagedData}) => {
          pagedData.data = users;
          return pagedData;
        })
      );
  }

  public followSaleforceLink(pagedData: PagedData<User>): Observable<User[]> {
    return forkJoin(
      pagedData.data.map((user: User) => {
        const saleForceEndpoint = _.find(user.links, 'saleforces');
        return this.getRaw<SaleForce>(saleForceEndpoint.saleforces).pipe(
          map((saleForce: SaleForce[]) => {
            user.saleForces = saleForce;
            return user;
          })
        );
      })
    );
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM