Troubleshooting problems with resolving deeply nested promises

My approach to utilizing promises has been effective until now. The issue arises when the console.log(this.recipe) returns undefined and

console.log(JSON.stringify(recipes))
displays an empty array. This suggests that the nested promises may not be resolving correctly.

  ngOnInit(): void {
   this.recipeService.getAllRecipesByUserId().then((recipes) => {
   this.allRecipes = recipes;
   this.recipe = this.allRecipes[0];
   console.log(this.recipe);
 });
}

The expected return type of the getAllRecipesByUserId() function is a promise with Recipe[] data.

  async getAllRecipesByUserId(): Promise<Recipe[]> {
  let recipes: Recipe[] = [];

  await this.userService.userRecipeIds().then((ids) => {
   ids.forEach((id) => {
     const q = query(this.recipeCollection, where('id', '==', id));
     getDocs(q).then((querySnapshot) => {
       querySnapshot.forEach((doc) => {
         recipes?.push(doc.data() as Recipe);
       });
     });
   });
  });

   return recipes;
  }

In the userRecipeIds() method:

async userRecipeIds(): Promise<string[]> {
 let user: User = new User();
 const q = query(
   this.userCollection,
   where('userId', '==', this.auth.getCurrentUser()?.uid)
 );

 return await getDocs(q).then((querySnapshot) => {
   querySnapshot.forEach((doc) => (user = doc.data() as User));
   return user.recipes;
 });
}

Are the promises being resolved correctly in these methods?

EDIT:

I have made adjustments to the userRecipeIds() method as follows:

  async userRecipeIds(): Promise<string[]> {
    const q = query(
    this.userCollection,
    where('userId', '==', this.auth.getCurrentUser()?.uid)
  );

  const docs = await getDocs(q);
  const user = docs.docs[0].data() as User;
  return user.recipes;
 }

Subsequently, I refactored the getAllRecipesByUserId() like so:

  async getAllRecipesByUserId(): Promise<Recipe[]> {
    let recipes: Recipe[] = [];
    const userRecipes = await this.userService.userRecipeIds();

  userRecipes.forEach(async (recipeId) => {
    const q = query(this.recipeCollection, where('id', '==', recipeId));
    const querySnapshot = await getDocs(q);
    querySnapshot.forEach((doc) => {
      recipes.push(doc.data() as Recipe);
   });
 });

 return recipes;
}

However, the issue persists where the array remains empty when inspected within the ngOnInit().

Answer №1

I'm having trouble understanding your code completely, but I did notice a potential issue in this snippet. It seems like you are iterating over an array and assigning each item to a single field called user. However, after the forEach loop finishes, the field user will only have the value of the last item in the array, which is the last doc.

Perhaps the method should be structured more like this:

async userRecipeIds(): Promise<Recipe[]> {
 const q = query(
   this.userCollection,
   where('userId', '==', this.auth.getCurrentUser()?.uid)
 );

 const docs = await getDocs(q);
 const recipes = docs.map(doc => doc.data());

 return recipes;
}

If we only want the first element:

async userRecipeIds(): Promise<User> {
 const q = query(
   this.userCollection,
   where('userId', '==', this.auth.getCurrentUser()?.uid)
 );

 const docs = await getDocs(q);
 const user = docs[0].data();

 return user;
}

Based on that structure, the other function could potentially look like this:


 async getAllRecipesByUserId(): Promise<Recipe[]> {
  const recipes: Recipe[] = await this.userService.userRecipeIds();

  return recipes;
 }

In response to the edited question: When you need to resolve multiple promises simultaneously, such as when the promises are generated from items in an array, it's crucial to handle the results asynchronously. The forEach method does not ensure that all promises are resolved before completing. In such cases, you should use Promise.all to collect all promises and resolve them together into an array of results:


async getAllRecipesByUserId(): Promise<Recipe[]> {
    const userRecipes = await this.userService.userRecipeIds();
    const recipieQueries = userRecipes.map(recipe => {
        const q = query(...));
        return getDocs(q);
    })
    const recipes = await Promise.all(allRecipiesPromises);

    return recipes;
}

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

Acquiring the API through the callback function within a React application

I wrote a function that connects to an API and fetches data: import {API_KEY, API_URL} from "./constants"; export const getOperations = async (id, successCallback) => { try { const response = await fetch(`${API_URL}/tasks/${ ...

Encountering a "undefined response" issue within an Angular

I am encountering an issue when trying to fetch data from a REST API. Upon logging the response, I am getting an undefined value. How can I resolve this? I have confirmed that the API is sending data by checking my network tab in the developer tool. getPro ...

What are the steps for loading JSON data into a select dropdown with the help of AJAX?

I am trying to create a dropdown list of schools using the select tag. Currently, I have hard coded values for the list, but I want to fetch the data from a RESTful service instead. Can someone please provide guidance on how to achieve this? <html& ...

Rearranging div placement based on the width of the screen

I am currently working on building a responsive website and I need two divs to switch positions depending on the screen width, both on initial load and when resizing. Despite my efforts in researching and trying various options, I have not been successful ...

Is it possible to use multiple routes in the same page with Vue-router?

In the process of developing a Vue-based web application that utilizes vue-router in history mode, everything was functioning smoothly for navigating between various pages. However, a new request has been made to open certain pages within a virtual dialogu ...

Sidenav selector unable to display Angular component

I'm facing a dilemma. I have the following code in my app.component.html file: <mat-sidenav-container class="sidenav-container"> <app-sidenav></app-sidenav> <mat-sidenav-content> <app-header></app-header> ...

Update the WooCommerce shopping cart page automatically upon product removal

After trying to solve the issue of refreshing the cart page in WooCommerce when a product is removed, I came across this helpful question on Stack Overflow: Refresh the page after product remove from cart Woocommerce. Following the provided code snippet th ...

Issue encountered while configuring input in ReactJS: the label is conflicting with the input value, causing it to be overwritten when using material.ui components

Hello fellow developers! I am currently facing an issue in my reactJS project. I am using the react-form-hook along with Material-UI's TextField. The problem arises when I input data into a field named cep, triggering a function that fetches content ...

Stop the controller from reloading when navigating in Angular2/Ionic2

Initially, I developed my app using tabs. When navigating to a page, the view would load for the first time (fetch data from API and display it), and upon returning to the same page, nothing would reload because the controller did not run again. Recently, ...

Exploring the power of flow.js within an Angular 2 Typescript project

I am trying to incorporate flowjs or ng-flow into my Angular 2 application. After installing the flowjs typings using npm install --save-dev @types/flowjs from However, upon importing it into my component with import { Flow } from 'flowjs';, ...

The error message "element is not defined" is indicating an issue related to the cordova-plugin-google

In my current project using Ionic 3, I decided to implement map-related features by incorporating the Google Maps plugin recommended by the Ionic Team. This specific plugin serves as a wrapper around cordova-plugin-googlemaps. Following the steps outlined ...

How can a nullable variable be converted into an interface in TypeScript?

Encountered an issue while working on a vue3.x typescript project. The vue file structure is as follows: <template> <Comp ref="compRef" /> </template> <script lang="ts" setup> import {ref} from "vue& ...

Using jQuery to assign the value of a hidden element to data being posted

When using jQuery's post() method to call an ajax action that returns JSON data ({"Success": "true" } or {"Success": "false"}), the value of a hidden HTML element is supposed to be set to the Success value in the returned object. However, after settin ...

Having issues with Next.js server-side rendering when integrating API functionality

"Not building properly" means that the project is not fully completing the build process. I've developed a simple blog project with dynamic SSR that pulls data from the Notion-API to generate static blog pages. Everything functions correctly ...

Executing the serverless invoke local command produces no output

Attempting to locally run a node lambda for debugging purposes. Utilizing Serverless and the provided launch configuration in vsCode. { "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Launc ...

Concurrent Accordion and Color Transformation Animations

I am currently utilizing jQuery version 2.0.3 and jQuery UI version 1.10.3, specifically using the accordion feature. I am attempting to modify the color of the accordion panels as they open and close by implementing the following code: $(".main-content") ...

Generating npm package without including file extensions in imports

I am currently working on creating an internal library for my workplace. Everything seems to be going smoothly until I try to use it in another project. It appears that the file extension in all of the import statements has disappeared during the npm pack ...

Generating variables dynamically within a React Native component

In my React Native component, I need to create a variable that will be used multiple times. Each instance of this component should have a different variable name for reference. <View ref={view => { shapeView = view; }} onLayout={({ nativeE ...

Accessing JSON data and populating a dropdown menu with JQuery

I am facing an issue with extracting values from a JSON array using jQuery. The structure of the array is as follows: [{ "": "Select your State/Region" }, { "BAL": "Balkh" }, { "BAM": "Bamian" }] Although I have attempted to loop through the array in ord ...

Sending files to the server through HTML5

Could someone assist me with uploading a file after it has been selected using HTML5? Here's the code snippet for selecting the file: <input type="file" .... /> The input field above allows you to choose a file, but I also need help with uploa ...