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

Issue with vertical cell alignment in MUI x-data-grid persists following the latest update to version 7.2.0

After updating my MUI app to the latest npm packages version, specifically upgrading x-data-grid from 5.17.9 to 7.2.0, I encountered an issue. In my application, I utilize a grid where certain columns are populated using the renderCell property: const cel ...

I am wondering how to use the value assigned to a variable's textContent as an argument for player input in my JavaScript code

i am currently developing a JavaScript project to create a user interface for my rock, paper, scissors game. Currently, the game only runs in the console and prompts the player for input. So far, I have implemented three buttons (one each for rock, paper, ...

What is the best way to transfer data in a JavaScript onclick event and then retrieve it in the click handler function?

I've been struggling with this issue for some time now. When researching the onclick JavaScript call, I noticed that sometimes it is written as onClick with a capital C, while other times it's simply onclick. The code I'm working on is part ...

What is the method to define a function that strictly accepts a value of type T only if IsSomething<T> evaluates to true?

In my system, there is a complex generic type called IsUnique<T> that evaluates to either true or false based on the input type T: type IsUnique<T> = (/* ... */) ? true : false; Now I am looking to develop a function that takes an unique value ...

IntelliJ is not able to detect certain JS libraries

Currently, I am working on an NDV3 AngularJS graph demo using IntelliJ. To start off, I have created a standard HTML file named index.html and included all the necessary AngularJS and NDV3 libraries in a folder called bower_components located within the r ...

The simultaneous use of trackball controls and GUI is not compatible

When I click on them, the GUI changes together and I have looked at other answers. However, I am not sure where to put the listener. I tried putting the listener in render(), but it still doesn't work. How can I fix my code? This coding is related to ...

How to retrieve only the last value from a JSON object using jQuery's .html

I'm having an issue with jQuery("#someID").html. It seems to only display the last name from the JSON data. Here is the javascript code: <div class="row" id="fetchmember"> <script type="text/javascript"> jQuery('#group').cha ...

When the application is converted into static files, the dynamic routes fail to function properly

I have a website that is statically exported but has dynamic routes. During development, the site works fine. However, when I build and export it, then serve the static files using serve, an issue arises. If you go to the site root and click on a link th ...

Encountered an issue with instafeed.js due to CORS policy restrictions

Trying to implement an API that provides JSON data for use in a function. Required Imports: Importing Jquery, instafeed.min.js, and the API (instant-tokens.com). <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js& ...

There was an issue retrieving the value from the $.ajax() error function, as it returned [

After successfully receiving data from the input field and sending it to the database, everything seems to be working fine. However, when attempting to retrieve the data after sending it to the database, an error is encountered: [object HTMLInputElement]. ...

Restart animation following a scroll occurrence

My experiment involves using the anime.js framework to create a simulation of leaves falling from a tree. The animation triggers when the user scrolls to the top of the page. However, I am facing an issue where the animation only plays once; if the user sc ...

When trying to install my npm package from the registry, I keep encountering an issue despite being able to install it locally

I recently released my Node.js/typescript package on the npm registry, but I'm encountering issues when trying to install it from there. Oddly enough, local installation works perfectly fine. Here's the output from the local installation: $ npm ...

Navigate to a different directory within Cypress by utilizing the cy.exec() function

Dealing with cypress to execute a python script in another directory. However, it seems like the directory change is not functioning as expected. visitPythonProject() { cy.exec("cd /Users/**/Desktop/project/"); cy.exec("ls"); // thi ...

Tips for displaying the initial slide when a tab is loaded on a multi-tab webpage

I have a total of four tabs, with the first tab containing a slideshow. On page load, I am successfully triggering the first tab, but for some reason, the first slide in the slideshow within that tab is displaying a blank image. I'm struggling to find ...

What is the best way to monitor different selections to keep track of their state?

In a certain scenario, a user is presented with three options: They can select the body_type of a car, the car_year it was manufactured, or the car_make. Initially, there is a state called carJson which contains a list of cars. "2": { " ...

Is there a way to determine the path of the fetch function within a PHP file?

I am using a JavaScript function to retrieve data from the backend server async getAllExpensesByUser() { let response = await fetch("router.php/getAll"); return response.json(); } My question is, how can I retrieve the path "/getAll ...

Limiting client requests on the Azure Translation API

I have a client who needs to limit the number of requests made to my Azure Translation API service. I found information from Microsoft on how to implement request throttling, but it's unclear where exactly in the request this throttling data should be ...

Angular Jasmine Test: Anticipated the invoked spy to have been executed

Examining a confirmation dialog in Angular 8 has led to an interesting discovery: one test passes while others fail, even though they are quite similar. The tests being conducted are for three statuses: Approve, Reject, and Reset. Interestingly, the test f ...

Sending a concealed input according to the chosen option

I'm attempting to send some hidden values to a Servlet via a form, but my goal is to only pass them if the user chooses a specific option. <!-- FORM ABOVE --> <input type="hidden" name="foo" id="foo" value="foo"> <input type="hidden ...

Warning: Unhandled Promise Rejection - Alert: Unhandled Promise Rejection Detected - Attention: Deprecation Notice

Encountering the following error message: (node:18420) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'name' of undefined at C:\Users\ohrid\Desktop\backend2\routes\categories.js:27:24 at Layer.han ...