Search code examples
javascriptfirebasefirebase-realtime-databasepromisees6-promise

Pushing into array from inside a for loop - inside of promises


In my project I am getting order id's from firebase and then getting each order based on that id and finally want to push that order to my orderList array.

But orderList array is always empty, I think there is a problem when pushing values into array from inside a for loop but couldn't find a solution.

How can I fix this and push the values to orderList?

fetchOrders({commit, getters, state}) {
    var orderList = [];
    service.fetchUserOrdersIds(getters.user.id).then(snapshot => {
        var tempOrderIds = snapshot.val();
        for (let key in tempOrderIds) {
            firebase
                .database()
                .ref("orders")
                .child(tempOrderIds[key])
                .once("value")
                .then(orderSnap => {
                    orderList.push(orderSnap.val());
                });
        }
    });
    commit("setUserOrders", orderList);
}

EDIT: I have found a solution but its a bit dirty. There might be a better solution I think

    fetchOrders({commit, getters, state}) {
    var orderList = [];
    service.fetchUserOrdersIds(getters.user.id).then(snapshot => {
        var tempOrderIds = snapshot.val();
        var size = Object.keys(tempOrderIds).length;
        var i = 0;
        for (let key in tempOrderIds) {
            firebase
                .database()
                .ref("orders")
                .child(tempOrderIds[key])
                .once("value")
                .then(orderSnap => {
                    orderList.push(orderSnap.val());
                    if (i == size) commit("setUserOrders", orderList);
                });
            i++;
        }
    });
},

Solution

  • Your commit() function was receiving an empty orderList because it was being fired before the promise that filled the orderList was fulfilled.

    Here is a simple modification that keeps the code structure you setup - but waits to fire the commit() function until the orderList array is generated:

    fetchOrders({commit, getters, state}) {
        return service
            .fetchUserOrdersIds(getters.user.id) // promist to get snapshot
            .then(snapshot => { // promise to generate orders list based on snapshot
                var listOfOrderPromises = [];
                var tempOrderIds = snapshot.val();
                for (let key in tempOrderIds) {
                    var thisOrderPromise = firebase // create a promise to get this order value
                        .database()
                        .ref("orders")
                        .child(tempOrderIds[key])
                        .once("value")
                        .then(orderSnap => {
                            return orderSnap.val();
                        });
                    listOfOrderPromises.push(thisOrderPromise); // append this promise to a list of promises (one for each order)
                }
                return Promise.all(listOfOrderPromises); // resolve all of the promises: generates your expected `orderList`
            })
            .then((orderList)=>{ // commit the orders from the resolved order List
                commit("setUserOrders", orderList);
            })
    }
    

    Note that the Promise.all() function takes an array of promises (e.g., [promise_1, promise_2, ...]) and resolves with an array of the values that resolve from each individual promise (e.g., [result_of_promise_1, result_of_promise_2, ...])