Retrieving objects from Firebase in a loop using promises

Seeking guidance on handling promises in AngularJS as a newcomer. Struggling with merging data from two asynchronous arrays into a single array within a for-loop. Encountering a bug where the same picture is displayed for all entries despite different user data. The issue seems to lie in the code snippet below:

userPromise.then(function(user){
        picPromise.then(function(url){
            newfriendsinfo.push({
                id: newfriendid,
                name: user.val().name,
                email: user.val().email,
                agreed: newfriendagreed,
                profilepicture: url
            });
        }).then(function(){
            if (newfriendsinfo.length == newfriends.length){
                deferred.resolve(newfriendsinfo);
            }
        });
    });

The challenge is apparent, but solutions like multiple deferred variables and $q.all haven't provided a clear path forward. Your input is valued, thank you :)

var friendsRef = firebase.database().ref('friendships/' + firebase.auth().currentUser.uid);

$scope.friends = $firebaseArray(friendsRef);

$scope.friendsinfo = [];

$scope.$watch('friends', function() {
    var newfriends = $scope.friends;

    asyncUpdateFriendsInfo(newfriends).then(function(newlist){
        $scope.friendsinfo = newlist;
    });
}, true);

function fetchPicture(ref){
    return ref.getDownloadURL().then(function(url) {
        return url;
     }).catch(function(error) {
        alert("error");
    });
}

function fetchUserInfo(ref){
    return ref.once('value', function(snapshot){

    }).then(function(snapshot){
        return snapshot;
    });
}

function asyncUpdateFriendsInfo(newfriends){
var deferred = $q.defer();
var newfriendsinfo = [];

for(var i = 0; i < newfriends.length; i++){
    var ref = firebase.database().ref('users/' + newfriends[i].$id);
    var profilePicRef = firebase.storage().ref("profilepictures/" + newfriends[i].$id + "/profilepicture");
    var userPromise = fetchUserInfo(ref);
    var picPromise = fetchPicture(profilePicRef);

    var newfriendid = newfriends[i].$id;
    var newfriendagreed = newfriends[i].agreed;

    userPromise.then(function(user){
        picPromise.then(function(url){
            newfriendsinfo.push({
                id: newfriendid,
                name: user.val().name,
                email: user.val().email,
                agreed: newfriendagreed,
                profilepicture: url
            });
        }).then(function(){
            if (newfriendsinfo.length == newfriends.length){
                deferred.resolve(newfriendsinfo);
            }
        });
    });
}

return deferred.promise;

}

Answer №1

There is a clear issue within this particular piece of code.

userPromise.then(function(user){
    picPromise.then(function(url){

The problem lies in the nesting of promises, which does not ensure that userPromise will resolve before picPromise.

These are two separate asynchronous calls. If picPromise resolves first, the subsequent code will not execute.

newfriendsinfo.push({
    id: newfriendid,
    name: user.val().name,
    email: user.val().email,
    agreed: newfriendagreed,
    profilepicture: url
});

Additionally, even if userPromise resolves prior to picPromise, issues will persist. The variables newfriendid and newfriendagreed are utilized within a promise created outside of the cycle, resulting in a closure problem.

Here's what occurs when the asyncUpdateFriendsInfo function is invoked.

Upon completion of the for loop, all requests are made (though responses have yet to be received) and newfriendid and newfriendagreed point to the last record's $id and agreed within newfriends. Consequently, all newfriendids within newfriendsinfo will be identical and correspond to the final newfriendid.

Refer to this resource regarding "Asynchronous Process inside a javascript for loop" for more insights.

It's advisable to substitute the existing code with something like

(function(newfriendid){
    var finalUser, 
        finalUrl;

    userPromise.then(function(user){
        finalUser = user;
        checkIfBothLoaded();
    });

    picPromise.then(function(url){
        finalUrl = url;
        checkIfBothLoaded();  
    });

    function checkIfBothLoaded(){
        if (finalUser && finalUrl){
            newfriendsinfo.push({
                id: newfriendid,
                name: finalUser.val().name,
                email: finalUser.val().email,
                agreed: newfriendagreed,
                profilepicture: finalUrl
            });
        }

        if (newfriendsinfo.length == newfriends.length){
            deferred.resolve(newfriendsinfo);
        }
    }

})(newfriendid, newfriendagreed);

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

Align the camera to be perpendicular with the ground

Ensuring that my fly camera always remains parallel to the ground is crucial to me. Specifically, I need my camera's right vector to always be (1,0,0). To achieve this, I have developed a customized Camera Controller in three.js that simulates unique ...

Sending POST Requests with Node and ExpressJS in the User Interface

Just diving into the world of Node.js and Express.js, I'm attempting to create a form submission to an Express.js backend. Below is a snippet of the code I am working with: var author = 'JAck'; var post = 'Hello World'; var body ...

To effectively utilize the expect function in testing, should you use it over softAssertAll or find a way to explicitly display in the test results that the softAssertAll has successfully passed? (Error

Utilizing the 'soft-assert' library (soft-assert library) allows me to implement assertions in my test steps without halting the entire test if any of them fail. While softAssertAll() command works effectively to verify all soft-assert at the en ...

Incorporate HTML and JavaScript to dynamically show a button when a specified condition evaluates as true and hide the button if the

I need help with a scenario where I want to show a button only when a specific variable reaches a certain value. For instance, if the variable equals 5, the button should be displayed; otherwise, it should be hidden. Here are the two buttons included withi ...

Using ThreeJS to project a texture onto a mesh surface

I am trying to project a texture onto the surface of a mesh using ThreeJS. The link provided achieves the desired result, although I am uncertain about the method used to accomplish it. . As I continue my research, I will update this post. If anyone has ...

Is there a simple way to delete an element from a multidimensional array object in React JS?

In my current project using React Js, I'm facing an issue with removing an item that corresponds to the "product_option_value_id". The task at hand is to remove an item from the product_option_value (a child array object) if the given itemId matches t ...

Implementing NodeJS to showcase an array of items - the step-by-step guide

I'm currently setting up a webpage to display a list of books using NodeJS, but despite my efforts, the page remains blank when I launch it. My goal is to showcase the array of books on the page, and so far, here's the code that I have written. A ...

Acquiring the specific checkbox value using JQuery

I am encountering an issue with my JQuery function that is supposed to print out the unique value assigned to each checkbox when clicked. Instead of displaying the correct values, it only prints out '1'. Each checkbox is assigned an item.id based ...

When using the .after() method to add jQuery elements, keep in mind that they will not trigger any

Here is the snippet of code provided: <s:file name="upload" id="upload"></s:file> $('input[id^="upload"]').change(function(){ alert("aa"); $(this).after('<input type="file" name="upload_3" id="upload_3"/> ...

The expected behavior is not displayed when using Async.waterfall within a promise queue

In our software implementation, we have utilized a promise queue feature using the q library. The sequence of functions is structured as follows: PQFn1 -(then)- PQFn2 - .... Within PQFn1, an array of values is passed to a callback function implemented wi ...

implementing multiple updates in Mongoose for MongoDB

There are often times when I need to make multiple update requests based on various conditions. if (some true condition) { let recordBeforeUpdate = await this.PatchModel.findOneAndUpdate({ "_id": patchId }, { $inc: { inStockPallets: -1, f ...

Node.js - Issue with res.json function: inconsistency across different routes

Currently working with the MERN stack (Mongo, Express, React, Node) and encountering an issue in my API. Here is a snippet from my plaid.js file where one of my routes is causing an error. I have omitted any sensitive information such as secret tokens, bu ...

Causing a click event to occur results in crashing the browser

Take a look at this link: example on jsfiddle Why does the click event keep triggering multiple times when a div is clicked, eventually causing the browser to crash? What could be causing this issue and how can it be resolved? The actual div contains a l ...

Feeling uncertain about Node, NPM, Bower, and how to set them up for Bootstrap?

Looking to expand my knowledge in web development, I have a solid understanding of HTML, JS, CSS, and server-side programming. However, the concepts of Nodejs, npm, and Bower are still unclear to me. In order to begin a new project, I created a designated ...

Sending data via req.body from middleware

One middleware function is defined as follows: app.use('api/', authenticate, bar); In the authenticate function, a variable is being attached to req.body like so: req.body.user = foo; However, when trying to access req.body.user inside the ba ...

Create a connection between a div and a React component, allowing for the seamless transfer of

I'm looking to implement a feature where clicking on a specific div will redirect the user to another page, similar to React Router. However, I currently lack the knowledge to make it happen. Below is the code snippet in question: const Card: React.FC ...

Beginner coding exercises to master JavaScript

With a proficiency in CSS, HTML, and some knowledge of Jquery and PHP, I aspire to become a Front End Web Developer. However, my lack of understanding in Javascript is holding me back. I acquired my current skillset by rapidly learning over 9 months while ...

Search a location database using the user's current coordinates

Currently, I am working on a project that involves a database containing locations specified by longitude and latitude. Upon loading the index page, my goal is to fetch the user's location and then identify every point within a certain distance radius ...

Managing data binding and events in AngularJS 2.0

Recently, I have been experimenting with AngularJS 2.0 and trying out different features. In a simple scenario, I have implemented a select box that is linked to a property of a component attribute like this: <select [(ngModel)]="zeitraum" [value]="ze ...

Having trouble retrieving values from JSON properties

My mind is boggled by this issue, and I have a feeling it's just a simple oversight! I'm dealing with a service that sends back a JSON object: [{"accountId":"0000004000006195","title":null,"firstName":"JOE","middleName":"BLOG","lastName":"BLOGG ...