Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to repeat same network request multiple times with different parameters in rxjs (Angular)?

I have a mat-table element and a mat-paginator element below. The table is filled with data from API. My API returns 10 elements by request by default, but I need to display 25 elements in my table, hence I need to make 3 API requests to fill the mat-table.

How to repeat the call to API, with different argument and then return combined all three responses into one observable?

In my case - I want to repeat getPlanetsPage(pageNumber) with different pageNumber, so this is the tricky part (I tried to solve this by repeat()...):

return this.planetService.getPlanetsPage(dontKnowHowToDoItArg)
  .pipe(
    repeat(Math.ceil(this.paginator.pageSize / this.countOfPlanetsPerPage))
  );

Whole code from ngAfterViewInit() :

this.paginator.page
  .pipe(
    startWith({}),
    switchMap((paginatorData) => {
      this.isLoadingResults = true;

      const indexOfFirstElementToRenderInTable = this.paginator.pageSize * this.paginator.pageIndex;
      if (this.planets[indexOfFirstElementToRenderInTable]) {

        this.planetsToRender = this.planets.slice(indexOfFirstElementToRenderInTable, this.paginator.pageSize * (this.paginator.pageIndex + 1));
        return EMPTY;
      } else {
        return this.planetService.getPlanetsPage(dontKnowHowToDoItArg)
          .pipe(
            repeat(Math.ceil(this.paginator.pageSize / this.countOfPlanetsPerPage))
          );
      }
    }),
    map(planetsPage => {
      this.isLoadingResults = false;
      this.isRateLimitReached = false;
      this.resultsLength = planetsPage.count;
      return planetsPage.results;
    }),
    catchError(() => {
      this.isLoadingResults = false;
      this.isRateLimitReached = true;
      return of([]);
    })
  ).subscribe((planetsArr: Planet[]) => {
    this.planets.push(...planetsArr);
    const indexOfFirstElementToRenderInTable = this.paginator.pageSize * this.paginator.pageIndex;

    this.planetsToRender = this.planets.slice(indexOfFirstElementToRenderInTable, this.paginator.pageSize * (this.paginator.pageIndex + 1));
    this.requestNo++;
  });

http service get method:

getPlanetsPage(pageNumber): Observable<any> {
  return this.httpClient.get(this.planetsBasicPageUrl, {
    params: new HttpParams()
      .set('page', pageNumber.toString())
  });
}
like image 783
Aleks Grunwald Avatar asked Nov 16 '22 09:11

Aleks Grunwald


1 Answers

There is an rxjs operator dedicated for recursive calls, check EXPAND. Here is what will work for you

import { from, EMPTY } from 'rxjs';
import { expand, tap, switchMap } from 'rxjs/operators';
...



let results = [] // to concatenate your data each time
let pageNumber = 1; // to count your calls, you need 3 calls so it will be your stop condition



getPlanetsPage(pageNumber): Observable<any> {
 return this.httpClient.get(this.planetsBasicPageUrl, {
   params: new HttpParams()
  .set('page', pageNumber.toString())
 });
}


getPlanetsPage(1).pipe(
  tap(res => {
       this.pageNumber++; 
       results = results.concat(res)  // on success add new results to our array
     }),
  expand((_) => this.pageNumber <=3 
         ? getPlanetsPage(this.pageNumber)
         : EMPTY;
  )
).subscribe(console.log)

it's short and clean, you can check my post on dev.to about recursive calls https://dev.to/fatehmohamed14/recursive-http-calls-the-rxjs-way-d61

like image 124
Fateh Mohamed Avatar answered Mar 16 '23 00:03

Fateh Mohamed