fatihsolhan
fatihsolhan

Reputation: 565

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++;
        }
    });
},

Upvotes: 1

Views: 658

Answers (2)

Ulad Kasach
Ulad Kasach

Reputation: 12808

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, ...])

Upvotes: 1

Dai
Dai

Reputation: 155055

(Disclaimer: I'm not a Firebase user, but assuming it uses JavaScript Promises (Promise<T> in TypeScript) the way I'm used to, then something like this should work.

Note the use of Promise.all so that it waits for all of the firebase.database()... calls/promises to complete before passing the resolved values into commit( "setUserOrders", ... ).

service
    .fetchUserOrdersIds( getters.user.id )
    .then( snapshot => {
        var tempOrderIds = snapshot.val();
        var size = Object.keys( tempOrderIds ).length;
        var i = 0;

        var promises = tempOrderIds
            .map( orderId => firebase
                .database()
                .ref( "orders" )
                .child( orderId )
                .once( "value" )
            );

        Promise
            .all( promises )
            .then( orderValues => {
                orderValues = orderValues.map( e => e.val() );
                commit( "setUserOrders", orderValues );
            } );
    }

Upvotes: 1

Related Questions