Utilizing recursive techniques with expand() and concatMap() in Angular 7

Below is a list of APIs I am working with:

1. https://www.something.com/?filter=something

Result: 
{ 
  id: 12
  previous: null
  next: https://www.something.com/?filter=something&page=2
  data: ...
}

2. https://www.something.com/?filter=something&page=2

Result: 
{ 
  id: 13
  previous: https://www.something.com/?filter=something
  next: https://www.something.com/?filter=something&page=3
  data: ...
}

3. https://www.something.com/?filter=something&page=3

Result: 
{ 
  id: 14
  previous: https://www.something.com/?filter=something&page=2
  next: null
  data: ...
}

I am attempting to loop through all the URLs, gather and combine the data from each API call, and only continue if the 'next' variable is not null.

This is my current approach:

 getByURL(url: string): any {
    return this.apiService.get(url).pipe(map(data => data));
  }

  getData(): Observable<any> {
    const url = 'https://www.something.com/?filter=something';
    return this.getByURL(url).pipe(
      expand(({ data }) => {
        if (!data.next) return this.getByURL(data.next);
        else return empty();
      }),
      concatMap(({ content }) => {
        return of(content.data);
      })
    );
  }

However, I am getting undefined results after trying for several days. Any help would be appreciated. Thanks!

UPDATED

I have shared my code on stackblitz: I am making 3 API calls :

http://5cf15627c936cb001450bd0a.mockapi.io/users
http://5cf15627c936cb001450bd0a.mockapi.io/users2
http://5cf15627c936cb001450bd0a.mockapi.io/users3

I am aiming to collect all the data from each request. Please check the console in the provided link to see the output. I keep getting undefined. Thank you

https://stackblitz.com/edit/angular-rai6az?file=src%2Fapp%2Fapp.component.ts

Answer №1

I updated the code for you as shown below (updated stackblitz)

  ngOnInit() {
    this.getByPageNext()
      .subscribe(data => {
        console.log(data);
      });
  }

  get(url: string): Observable<any> {
    return this.httpClient
      .get(url)
      .pipe(catchError(this.formatErrors));
  }

  formatErrors(error: any) {
    console.error('error', error);
    return throwError(error.error);
  }

  getByURL(url: string): any {
    return this.get(url);
  }

  getByPageNext(): Observable<any> {
    const url = 'https://5cf15627c936cb001450bd0a.mockapi.io/users2';
    return this.getByURL(url)
      .pipe(
        expand((response: Array<any>) => {
          if (response && response.length && response[0].next) {
              return this.getByURL(response[0].next);
          }
          else {
            return empty()
          }
        }),
        map(obj => obj[0]), 
        reduce((acc, x: any) => acc.concat([x.data]), []),
      );
  }

This will concatenate all data into an array and the recursive HTTP calls will function correctly.

The only issue arises when calling '' because the next URL is http instead of https, causing an HttpError -> ProgressEvent.

Therefore, I started from '' which resolved the issue. Once the backend is corrected to use the proper link, you can revert back to your original request.

Another point to note is that the API result returns an array, not an object, hence why I accessed result[0]

Furthermore, your condition to return empty() was reversed.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Implement a personalized click function for the delete icon in the mini cart

Is there a way to customize the click event for the remove button in the mini cart? function ajax_call(){ $.ajax({ url: ajax_url, type: 'post', data: {action : 'remove_from_cart','cart_item_key' : 10}, ...

Acceptable choices for inclusion in .on when utilized as a proxy

According to the documentation on jQuery, it is stated that a selector needs to be passed in as a string to the .on() method. For example: $('#someEl').on('click', '.clickable', function() { /* ... */ }); Interestingly enoug ...

Constructor for Mongoose schema not being detected

I am facing an issue in my Node server where I am using Mongoose with a User schema to create a signup function. The error message I am receiving is: TypeError: this is not a constructor This error is coming up in the following code block: var mongoos ...

Is there a way to prevent a web page from refreshing automatically for a defined duration using programming techniques?

I am currently working on a specific mobile wireframe web page that includes a timer for users to answer a question after the web content body has loaded. There are two possible outcomes when answering the question: 1) If the user fails to answer in time, ...

Can JavaScript/jQuery be integrated with MySQL/PHP?

I have a unique question that I've been unable to find an answer to, which may indicate its complexity. The reason for my inquiry is because I am in the process of developing a food delivery website. Within the admin panel of this website, administrat ...

Component inside a shared module experiencing issues with router link functionality

I have developed a module called "Customer" that consists of components like login, home, and register. Additionally, I have created a shared module with components such as header and footer. Since the header and footer are meant to be shared across all co ...

"Implementing a Where Clause with Knex.js: Understanding the Necessity of Using Mandatory AND

I have a database table in SQLite that contains information about employees Table Name: Employee ID Name Country CountyID Status 1 John IN 1 Active 2 Jack US 1 InActive 3 Emma UK 1 ...

"Sending an Angular post request results in the transmission of an [object Object

I am a beginner in angular and currently involved in a project using angular 6 with Spring Boot 2. Here is the TypeScript class I am working with: export class Partner { constructor ( public id: number, public name: string, public email: ...

What are the various ways to display time zone in a different format?

I need to display the timezone in a unique manner. I have captured the user's timezone in a variable called timeZone, which currently returns the value as Asia/Calcutta. console.log(timeZone) // "Asia/Calcutta" Is there a way to showcase the timezon ...

Is there a streamlined approach to signal a successful callback to $q.all without the need to define a $q.defer() variable?

Within my application, I have a mixture of synchronous and asynchronous methods. Here is an example of code from one of the controllers: $q.all([ asyncMethod1(), syncMethod1() ]) .then(function (results) { Even though I don't actually need t ...

Guide to troubleshooting JavaScript in Firefox using Visual Studio 2008?

In the header section of my ASPX page, I have some scripts that I would like to debug with breakpoints in Firefox. ...

JS/Apps Script: Passing object and its keys as function parameters

When working with Google Apps Script, I have a specific task that involves looping through data and writing only certain keys to a sheet. I want this looping operation to be done in a separate function rather than directly in the main function, as it will ...

What is the best way to create a reset button for a timing device?

Is there a way to reset the timer when a button is clicked? Having a reset button would allow users to revisit the timer multiple times without it displaying the combined time from previous uses. Check out this code snippet for one of the timers along wit ...

I'm having issues with my pop method - it doesn't seem

Hello everyone, I am new to core JavaScript and currently learning how to create an array. I have written the following code but for some reason, the pop method is not working as expected. var players=['david','micky','Ryan' ...

Ways to handle display glitches while a user is scrolling

As I work on developing a web application that displays all shops managed by the user currently logged in, I am faced with an array on the client side continuously fetching shop data from a database. In React's perspective, the rendering of shops app ...

The Check-All checkbox retains the ng-model without any modifications

I implemented this jQuery script to create a check-all checkbox that, when clicked, ticks all checkboxes: function checkAll(e) { var check = $(e).is(':checked'); if (check) { $('[name="row_Checkbox"]:not(:checked)').tri ...

What is the best way to create a shell script using Node.js?

Currently, I am looking to utilize a shell script with NodeJs on my Windows platform to read a CSV file, perform processing via REST API call, and save the output in another CSV file. ...

Retrieving PHP information in an ionic 3 user interface

We are experiencing a problem with displaying data in Ionic 3, as the data is being sourced from PHP REST. Here is my Angular code for retrieving the data: this.auth.displayinformation(this.customer_info.cid).subscribe(takecusinfo => { if(takecusi ...

An improved method for fetching data from the server at regular intervals of x minutes

Is setInterval the best way to periodically check for updates in a database and update the UI accordingly, or are there better approaches that I should consider? I've read conflicting opinions on using setInterval for this purpose, with some sources ...

Guide on exporting values from a Promise within an imported module

Recently, I encountered a challenge where I needed to integrate a pure ESM package into a non-module. Unfortunately, modifying the script to accommodate this requirement was not an option. To tackle this issue, I turned to using the import() function (als ...