Combining various API requests within a Vue component, which includes a for loop

I'm delving into the world of API chaining, specifically trying to link two different API calls within a 'notes' Vue component. My knowledge of promises is basic at best, but I'm eager to enhance my skills in this area.

The initial API call retrieves all notes and stores them in an array using a Vuex mutation. Additionally, during this call, I create an object by mapping users' emails.

With this mapped object in hand, I embark on a second API call within a for loop to fetch all users' avatars.

The structure of the first API call appears like this:

getAllNotesAPI(entity) {
  noteService.getNotes(entity)
    .then((response) => {

      if (response.data.length === '0') {
        // Setting 'hasData' to false when response is empty
        this.hasData = false;
      } else {
        // Using a store mutation to add data to the note array
        this.setAllNotes(response.data);
      }

      // Mapping users' emails into 'userEmails'
      this.userEmails = [...new Set(response.data.map(x => x.userEmail))];

      // Triggering second API call here to retrieve all avatars associated with these emails
      for (let i = 0; i < this.userEmails.length; i++) {
        this.getAvatarAPI(this.userEmails[i])
      }
    })
    .catch((error) => {
      console.log(error);
    })
    .finally(() => {
      this.endLoader('notes');
    });
},

this.getAvatarAPI, representing the second API call, follows this format:

getAvatarAPI(login) {
  userService.getAvatar(login)
    .then((response) => {

      let newAvatar = {
        userEmail: login,
        picture: response.data.picture
      };
      // Storing the response in a userAvatar Object using a store mutation
      this.setUserAvatar(newAvatar);
    }).catch((error) => {
      console.log(error)
  })
},

Although I attempted utilizing async/await, I couldn't grasp how to bind 'this' within an async function (resulting in undefined when calling `this.getAvatarAPI(this.userEmails)`). I also experimented with chaining multiple then methods, but struggled to sequentially: retrieve all notes, fetch all avatars, and terminate the 'note' loader upon completion of both API calls.

If anyone could provide some guidance or a starting point for a solution, it would be greatly appreciated!

Answer №1

While this may not directly relate to your issue, it's best to avoid unnecessary for loops:

Do you really need the index (i)?

  for (let i = 0; i < this.userEmails.length; i++) {
    this.getAvatarAPI(this.userEmails[i])
  }

If not, focus on the user email instead:

  this.userEmails.forEach(userMail => {
    this.getAvatarAPI(userMail)
  })

To handle promises in sync, make sure to return a promise:

  1. Ensure getAvatarAPI returns a promise
getAvatarAPI(login) {
  return userService.getAvatar(login).then(data => {}) // remember to include the return statement
  1. Collect the promises from getAvatarAPI
  let promises = this.userEmails.map(userMail => {
    return getAvatarAPI(userMail)
  })
  1. Only return once all promises are fulfilled
  let promises = this.userEmails.map(userMail => {
    return getAvatarAPI(userMail)
  })
  return Promise.all(promises)

A quick note about async/await:

Using async/await eliminates the need for explicit returns, but requires specifying await keyword:

The underlying concept remains unchanged. Declaring a function as async indicates it will return a promise-like object.

For example:

  async function p () {
    return 5
  }

  p.then(x => console.log(x)) // prints 5 without needing return Promise.resolve(5)

Just make sure to await the async function when calling it:

  getAvatarAPI: async login => {
    return userService.getAvatar(login).then(data => {})
  }

  // AVOID doing this
  this.userEmails.forEach(async userMail => {
    return await this.getAvatarAPI(userMail)
  })

In the above forEach loop, calls to getAvatarAPI will run in sequence due to await pausing iteration until resolution.

The correct approach is:

  getAllNotesAPI: async entity => {
    try { // don't forget the essential try-catch block
      const response = await noteService.getNotes(entity)
      handle data
      let promises = this.userEmails.map(userMail => {
        return this.getA...
      })
      let result = await Promise.all(promises)
      // eventually return result, or simply await Promise... without assignment
    } catch (error) {
      console.log(error);
    }
    console.log(this.end('loader'))
  }

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

Formik's handleChange function is causing an error stating "TypeError: null is not an object (evaluating '_a.type')" specifically when used in conjunction with the onChange event in DateInput

When using the handleChange function from Formik with the DateInput component in "semantic-ui-calendar-react", I encountered an error upon selecting a date. https://i.stack.imgur.com/l56hP.jpg shows the console output related to the error. AddWishlistFor ...

Having trouble with jQuery modal not adjusting its height properly

I am a jquery modal popup newcomer. I can open the modal when clicking on the hyperlink, but I'm having trouble with the height setting. Despite my attempts and searches online, I couldn't figure it out. When trying to post a question about the & ...

How to Utilize JQuery for Sticky Elements

I am experimenting with a unique twist on the classic Sticky Element concept. Check out for a typical sticky element example. Instead of the traditional sticky behavior, I am looking to have an element initially anchored to the bottom of the user's ...

Ways to determine if an element is at the top of a page

I need help with a test case that involves checking if the title scrolls up to the top of the page when a button is clicked. The challenge is that there is a default header on the page, so the title should scroll below that. How can we verify this scenar ...

Cut off all information beyond null characters (0x00) in Internet Explorer AJAX responses

When using Internet Explorer (IE6, IE7, and IE8), null characters ("0x00") and any subsequent characters get removed from ajax responses. Here's the code snippet that showcases a loop of AJAX requests: var pages = 10; var nextnoteid = 0; for (isub ...

How do server side cookies and javascript cookies interact with each other?

Can you explain the connection between the cookies generated by the Cookie Class in Servlet and document.cookie in JavaScript? ...

Animate out Material UI element with zoom effect and then remove it from the

I'm currently working on a dynamic user interface that allows for adding and removing items dynamically. Each item has both an add and remove button, with a special animation effect using Zoom. While this works smoothly when adding new items, I encoun ...

Guide on clearing the value of the first textarea and transferring it to the second textarea using JavaScript

I have encountered an issue where the first textarea value is being copied into the second textarea because I am using the same id for the 'add more' functionality. Below is the code snippet: <div id="divShortAnswerOption_Templated"> & ...

Unleashing the Power of RxJS with OR Conditions

I am working with two Observables. For instance, I am waiting for either an HTTP POST call or a WebSocket call to return so that I can proceed. Once either call returns, I need to verify the information until a certain condition is met. In the following e ...

Unable to switch checkbox state is not working in Material UI React

I am experiencing an issue with the Material UI checkbox component. Although I am able to toggle the state onCheck in the console, the check mark does not actually toggle in the UI. What could be causing this discrepancy? class CheckboxInteractivity exten ...

Errors are being thrown by 'npm run serve' due to the absence of FilterService

I've been working on a project using Vue.js and I keep running into an issue with npm. Every time I install it, I get errors saying that certain files are missing from the node_modules folder. When I try to run npm run serve, I encounter the followin ...

What could be causing the issue with my hour parameter in node-cron?

Having difficulty setting up a cron job to run with node-cron every Monday at 8:30. I've tried using "30 8 * * Mon" and even "30 08 * * Mon", but it doesn't seem to work. Interestingly, "30 * * * Mon" does work and runs every hour on the 30th min ...

Is it possible to utilize components or directives in both AngularJS and Angular when developing a hybrid application?

Is it possible to use AngularJS directives/services that have been "upgraded" in a hybrid app created with ngUpgrade for migrating from AngularJS to Angular? Can Angular components that are "downgraded" still be used on the Angular side as well? While res ...

What are the specific files I should modify for HTML/CSS in my Ruby application?

My application was initially created with an introduction from: http://guides.rubyonrails.org/getting_started.html I am now looking to add some color and style through CSS. I have located the JavaScript and CSS files, but I am unsure which file is respons ...

Modify text using JQuery when the span is clicked

Currently, I am attempting to retrieve a value from the database: SenderDriver->total_trips. Everything seems fine, but I have a specific id that needs to be placed within onClick(), which then sets the value of the database variable: SenderDriver-> ...

Using useState to initialize a long value

Obtaining a very large state from JSON can be challenging, especially when it consists of at least 50 lines. During page generation, an error like "there is no such value" may occur if the initial value is not set and the interface is not assigned properl ...

Is it possible to upload a file using Angular and ASP.NET Web API Core?

I am encountering an issue with CORS policy while making requests. It works fine when the content-type is set to 'application/json'. However, when I try to upload a file using content-type 'multipart/form-data', I receive an error: XML ...

The Vue router requires a page reload to see changes and does not have access to the this

When navigating through router-link, the App.vue page opens initially, but the URL changes immediately without displaying the content. Reloading the page is necessary to view it. If you navigate programmatically, you may encounter an error stating 'Ca ...

What's the best way to customize the color of the text "labels" in the Form components of a basic React JS module?

I have a React component named "Login.js" that utilizes forms and renders the following:- return ( <div className="form-container"> <Form onSubmit={onSubmit} noValidate className={loading ? 'loading' : ''}&g ...

Issue with Bootstrap v3.3.6 Dropdown Functionality

previewCan someone help me figure out why my Bootstrap dropdown menu is not working correctly? I recently downloaded Bootstrap to create a custom design, and while the carousel is functioning properly, when I click on the dropdown button, the dropdown-menu ...