0
function getPending(friendships) {
var myTable= "";
var userId = getUserId('username');
for(let key in friendships){
    if(friendships.hasOwnProperty(key)){
        if(friendships[key].recvId == userId) {
            // Do Something with it. Access it via users[key]
            myTable += "<div class='container'>";
            myTable += "<div class='row'>";
            myTable += "<div class = 'col-sm-4'>";
            var name ="";
            var ref = firebase.database().ref().child("Users");
            var foundUser = false;
            ref.orderByValue().on("value", function(snapshot) {
                snapshot.forEach(function(data) {
                    var user = data.val();
                    if(user.userId == friendships[key].sendId && foundUser == false) {
                        name += ("" + user.username);
                        foundUser = true;
                    }
                });
            });
            myTable += name + "</div>";
            myTable += "<div class = 'col-sm-4'>Be my friend!</div><div class = 'col-sm-4'>"
            myTable += "<button>Accept</button><button>Decline</button></div></div></div>"
            }
        }
    }
return myTable;
}

This is my code to show all pending friend requests.

the return statement runs before the for loop is finished and actually returns an empty string each time.

I think the problem lies with the line : ref.orderByValue().on("value", function(snapshot) { ....

How can I force javascript to run the return statement only after all the execution is finished?

adjuremods
  • 2,938
  • 2
  • 12
  • 17
doso13
  • 31
  • 1
  • 2
  • You cannot make the `return` 'wait', you will have to do your DOM manipulation in the callback passed to the `on` method or use Promises. – Jared Smith Oct 26 '16 at 21:59

1 Answers1

1

Here is the correct way to do that, first of all you need to use async library, so install that first, then you can use code like this.

        function getPending(friendships, cb) {
            var myTable= "";
            var userId = getUserId('username');
            async.each(Object.keys(friendships), function(key, callback) {
                if(friendships[key].recvId == userId) {

                        ref.orderByValue().on("value", function(snapshot) {
                            snapshot.forEach(function(data) {
                                        // Do Something with it. Access it via users[key]
                                myTable += "<div class='container'>";
                                myTable += "<div class='row'>";
                                myTable += "<div class = 'col-sm-4'>";
                                var name ="";
                                var ref = firebase.database().ref().child("Users");
                                var foundUser = false;
                                var user = data.val();
                                if(user.userId == friendships[key].sendId && foundUser == false) {
                                    name += ("" + user.username);
                                    foundUser = true;
                                }
                                myTable += name + "</div>";
                                myTable += "<div class = 'col-sm-4'>Be my friend!</div><div class = 'col-sm-4'>"
                                myTable += "<button>Accept</button><button>Decline</button></div></div></div>"
                                callback();

                            });
                        });

                    }
            }, function(err) {
                cb(err, myTable)
            })
    }

you can not just simply return table, it should be with callback or you can modify the way that would return promise

Vladimir Gabrielyan
  • 801
  • 1
  • 11
  • 23
  • Third-party libraries are *completely* unnecessary. – Jared Smith Oct 26 '16 at 21:59
  • it would not be easy to implement async loop, that is why I suggested to use `async` library – Vladimir Gabrielyan Oct 26 '16 at 22:02
  • Untrue. You just map a Promise-returning function over a list of values, then `Promise.all` the resulting array. Or if the calls need to be sequential, you can use a Promise-yielding generator. – Jared Smith Oct 27 '16 at 00:08
  • My point was even not to block the main thread during iterating over the array Object.keys. But if we assume that above array is not that big we could go with generators. It could be me more critical when you are dealing with server side code and every blocked milisecond costs you not to serve other requests. But ok, for this example i totaly agree we could use generators. – Vladimir Gabrielyan Oct 27 '16 at 05:47
  • "Block the main thread?" JavaScript is single-threaded. `async` doesn't magically add threads to JavaScript. – Jared Smith Oct 27 '16 at 10:23
  • 1
    let me give you an example. `for(var i = 1; i < 1000000000; ++i) { //Some computation work, which takes CPU time } //Some other Staff` As in javascript we have only one thread, when your interpreter reaches that code, it will block the main(and only one) thread let say for 5min, and during that you would not be able to perform any other staff, that is where come into help `async` loop, in that case you would not wait 5 min until your for loop will be reached to the end and you could perform other tasks as well. – Vladimir Gabrielyan Oct 27 '16 at 10:42
  • 1
    Alright, got what you mean now. Fair enough. – Jared Smith Oct 27 '16 at 13:29