What is the best way to construct a collection of promises' results by utilizing a for loop?

In the process of developing an Angular application to display articles and votes from my website, I aim to sort them based on their votes. The strategy involves making HTTP calls as follows:

  1. Initiate an HTTP call to fetch the list of categories along with their respective IDs for updating purposes due to frequent category additions on the website.
  2. Utilize these IDs to make individual HTTP calls for each ID in order to retrieve the articles associated with that specific category.
  3. Each article possesses its own unique ID which needs to be stored for subsequent HTTP calls dedicated to each article ID.
  4. The response object retrieved from step 3 contains a 'users_vote' property requiring the construction of an array to consolidate all votes and subsequently perform sorting operations before displaying the final array in HTML format.

I find it challenging to comprehend how to effectively chain promises, making the code serve as a reference to clarify the concept. Despite recognizing the complexity involved, I am constrained by the inability to introduce changes on the server side at present, compelling me to address the issue within existing parameters.

 ngOnInit() {
    this.getCategories()
    .then((res) => {
      this.getIds(res)
      .then((res) => {
        this.getArticlesList(res)
        .then((res) => {
          this.mergeArticlesList(res)
        })
      })
    })
  }


// 1) Retrieve the categories 

  getCategories() {
      var promise = new Promise((resolve) => {
        this.myService.getCategoriesList()
        .subscribe((res) => {
          this.categories = res;
          resolve(this.categories);
        })
      })
      return promise;
    }

// 2) Obtain the IDs of categories

  getCategoryIDs(res) {
    var promise = new Promise((resolve) => {
      for (let i=0; i < Object.keys(res).length; i++) {
        this.ids[i] = res[i+1]['id']
      }
      resolve(this.ids)
    })
    return promise;
  }

// 3) Fetch the list of articles under each category

  getArticlesList(res) {
    var promise = new Promise((resolve) => {
      for (let i=0; i < Object.keys(res).length; i++) {
        this.myService.getArticlesOfCategory(res[i])
        .subscribe((res) => {
          this.allarticleslist[i] = res;
        })
      }
      resolve(this.allarticleslist)
    })
    return promise;
  }

// 4) Merge the article IDs

  mergeArticleIds(res) {
    console.log("Start merging with:")
    console.log(res)
    console.log(res.length)
    console.log(Object.keys(res).length)
    for (let i=1; i < Object.keys(res).length -1; i++) {
      for (let _i=0; _i < res[i]['reviews'].length; _i++) {
        this.mergedArticles = res[i]['reviews'][_i]['id']      
      }
    }
    return this.mergedArticles
  }

// 5) Retrieve a specific article using its ID

  getArticle(res) {
    // ??
 }

}

An issue arises where console.log(res.length) returns 0, preventing the for loop from initiating. Addressing asynchronous operation timing concerns remains ambiguous, further complicating resolution strategies.

EDIT: Inclusion of getCategoriesList() method from myService:

getCategoriesList(): Observable<any[]> {
    let url = 'myurl';
    return this.httpClient.get(url)
}

EDIT2: Providing http.get response for getCategoriesList():

{"5":{"description":"","title":"SOCCER""term_id":280,"room_name":"SOCCER"},
"4":{"description":"","title":"NFL","term_id":281,"room_name":"NFL"},
"3":{"description":"","title":"MLB","term_id":282,"room_name":"MLB"},
"2":{"description":"","title":"NHL","term_id":283,"room_name":"NHL"},
"6":{"description":"","title":"TENNIS","term_id":284,"room_name":"TENNIS"},
"1":{"description":"","title":"F1","term_id":285,"room_name":"F1"}}

Answer №1

Below is a suggested code snippet you can try:

// To use this code, please ensure that this.myService.getCategoriesList() returns an observable containing all categories
    this.myService.getCategoriesList()
        .pipe(
          switchMap(categories => {
            // Note - Please replace 'cat.categoryId' with the property representing categoryId
            const observables = categories.map(cat => this.myService.getArticlesOfCategory(cat.categoryId));
            return forkJoin(observables);
          }),
          switchMap(arrayOfArticlesByCategoryId => {
            // Note - Please replace 'article.articleId' with the property representing articleId
            const observables = arrayOfArticlesByCategoryId.map(article => this.myService.getArticle(article.articleId));
            return forkJoin(observables);
          }),
          map(arrayOfallArticles => {
            // Alternatively, you can use the 'pluck' operator for extraction - https://www.learnrxjs.io/operators/transformation/pluck.html
            return arrayOfallArticles.map(article => article.users_vote);
          }),
          map(arrayOfUsersVote => {
            console.log(arrayOfUsersVote);
            // Perform any desired operations on arrayOfUsersVote, such as sorting
          })
        ).subscribe();

Answer №2

If you want to chain promises easily, one way is to create an array of promises like this

let gangOfPromises: Promise<any>[] = [];

Then, simply add a new promise to the array using the push method

var latestPromise = new Promise();
gangOfPromises.push(latestPromise);

To resolve all promises in your array, use

Promise.all(gangOfPromises).then((responses) => { ... })

I trust this approach will be helpful for you!

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

The Vue.createApp function seems to be malfunctioning, whereas using the new Vue() method is functioning correctly

When running my code, I encountered the following error message: tesyya.js:16 Uncaught TypeError: Vue.createApp is not a function. My code snippet looks like this: const app = Vue.createApp({ data() { return { count: 4 } } }) const vm ...

Prevent automatic submission of forms when selecting attributes in HTML forms using AngularJS

I need to create a form where users can select their branch of study. Here is the form I have designed- <form method="post" [formGroup]="formData" (click)="dataSubmit()" > <div class="form-group"> <label for="branch">Selec ...

Angular2 tubes sieve through hyperlinks within HTML content

As I receive HTML strings from an external source, my goal is to filter out all links that contain images, remove the href attribute, and replace it with a click event. I have attempted to achieve this using an Angular pipe, but so far I have only been suc ...

Attempting to retrieve the position of an image within an array upon clicking

function displayGalleryIndex(){ console.log($(this).index()); } $("body").on( "click", "#gallery img", displayGalleryIndex); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <section class="grid- ...

Send an array to a function with specified criteria

My current code successfully splits an array, but I need to pass a value when the array condition is met. For example, here is how the value is split into an array: var myArr = val.split(/(\s+)/); If the array in position 2 is empty, I need to use ...

"Exploring the Power of Vue 3 Event Bus Through the Composition API

I recently set up mitt and I'm facing difficulties dispatching events to another component. The issue arises due to the absence of this in the setup() method, making it challenging to access the app instance. Here's my current approach: import A ...

A guide on transforming a Firebase Snapshot child into a personalized object in a React Native environment

I'm looking for a way to retrieve data from Firebase Realtime Database and display it in FlatList format. What is the most efficient method for extracting the child value and converting it into a custom object? For example: class CustomObject { ...

Exploring the differences between importing all utilities as a whole using `import * as util from "./util"` and importing a specific function only with `import {someFunction

When comparing the two options of importing from a module, which is better: import * as util from "./Util" or import {someFunction} from "./Util"? ...

Creating keys from extensive JSON data without having to manually match types using Typescript

Is there a way to efficiently parse and access the values in large JSON files using Typescript, without the need to manually define interfaces for all expected key/value pairs? In the past, working with small JSON files required only extracting a few spec ...

Error: Spy creation was anticipated to have been invoked

Currently, I am in the process of writing unit test cases for an Angular 7 Component that utilizes an async service. Unfortunately, I encountered the following error: Error: Expected spy create to have been called once. It was called 0 times. Below is t ...

The functionality of Jquery Attr fails when not used in conjunction with the buttons tag

Having trouble with the atrr function not providing the desired response. I have a small code that retrieves data from an external API, which has multiple pieces of data in a dictionary. <div id="facet-knowledge-panel" style="margin-left: ...

jQuery-powered web application, experiencing compatibility issues when deployed on Windows Server 2003 and Internet Explorer

While developing a web application on XP and FF (with occasional IE checks through IE 8), I encountered an issue when deploying it to a WS 2003 site running IE 7. My jQuery code for dynamically sizing divs does not execute, even when explicitly stating div ...

What is the best strategy for managing various contexts in React?

Just diving into React - I've been experimenting with using multiple contexts in my App component. Following the instructions laid out in the official guide on working with multiple contexts. Let me share my current code: App.js import React from " ...

What's the best way to make the background image fill the entire page and have the buttons perfectly centered on top of the image?

I am currently working with Angular version 13 and have included the following CSS code. .image{ min-height: 100vh; background-position: center center; background-repeat: no-repeat; background-size: cover; back ...

Using angular2-google-maps in conjunction with an Angular2 application

I have successfully integrated the angular2-google-map with my angular2 application. Below is the content of app.module.ts file: import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; ...

Personalize Bootstrap 5 slider for mobile (displaying multiple items without being arranged in a single row)

Having trouble customizing the carousel layout for mobile devices. I'm trying to display all items of the carousel on mobile instead of just one. I've been experimenting with CSS and JS, specifically with the display, float, or max-width properti ...

The onValue event in Firebase is not triggering, and I am unable to determine the cause

I am currently working on a web3 application using Next/Js and Firebase. The concept is for users to connect with their Solana wallet, list their NFTs, and choose one to connect in a game-container. My challenge lies in retrieving information from all con ...

Guide on executing a method once a response is received from a previously called method

I am currently attempting to upload an array of files to a spring boot server. The issue I am facing is that each file is being saved one at a time. I am using a for loop to iterate through the file array and making a request for each file to be saved. H ...

Capture selected items from checkboxes and incorporate them into the CSS styling

I would like to give users the ability to choose from a series of checkboxes with additional options to add to their CSS. Using JavaScript, I am searching for checked boxes, extracting their names, adding them to a list, and then inserting that list into ...

Tips for refreshing the page upon Geolocation request

I am working on a HTML5 project that requests geolocation from the user. Here is an image of what it looks like: https://i.sstatic.net/o6yCj.png My main query is: Is there a way to refresh the page automatically once the user grants permission to share t ...