1

I am having an issue with some code which I would expect to work. I have a variable defined outside a function and as such would expect that to be available to the function through inheritance. I console log the variable outside the function and get a value and console log inside the function and get undefined. I have used comments in the code to show these console logs. Any help here would be great. Please see code snippet below. Thanks Ant

for (var i = 0; i < parseResult.length; i++) {

    var destination = parseResult[i].attributes.userInfo;

    for (var i = 0; i < firebaseResult.length; i++) {

        if (firebaseResult[i].$id == parseResult[i].attributes.facebookID) {


            parseResult[i].attributes.convoID = firebaseResult[i].convoID;

            console.log(firebaseResult[i].time); // this returns the timestamp value

            parseResult[i].attributes.lastMessage = FirebaseAPI.getLastMessage(firebaseResult[i]).$loaded()
                .then(function(lastMessage) {

                    console.log(firebaseResult[i].time); // this returns undefined

                    if (!(0 in lastMessage)) {

                        var returnValue = 'Matched on ' + firebaseResult[i].time;
                    } else if (0 in lastMessage) {

                        var returnValue = lastMessage[0].message;
                    }

                    return returnValue;

                })
                .catch(function(error) {
                    console.log("Error:", error);
                })

        }
    }
}
6
  • 6
    You're using i for both of the for loops, that is causing conflict. Use i and j for loops Commented Jun 30, 2015 at 8:48
  • 3
    @Tushar: that, and (even if he used different counters) both of them will likely be pointing to out-of-range of their respective arrays when a callback finally arrives. Commented Jun 30, 2015 at 8:51
  • 2
    duplicate of JavaScript closure inside loops – simple practical example Commented Jun 30, 2015 at 8:52
  • @SergioTulentsev Yes, for asynchronous operations inside for, anonymous function should be used inside for to preserve correct value of i or j Commented Jun 30, 2015 at 8:52
  • @Tushar: Better yet, a named function describing its purpose and being reused. Commented Jun 30, 2015 at 9:28

2 Answers 2

2

It is often not reliable to use loop iterator to access things in async callback, because when the callback come back, i would have been increased to the value that let it exit the loop.

The fix is assigning it to a variable for anything you want to hold.

console.log(firebaseResult[i].time); // this returns the timestamp value
var time = firebaseResult[i].time;

parseResult[i].attributes.lastMessage = FirebaseAPI.getLastMessage(firebaseResult[i]).$loaded()
   .then(function(lastMessage) {

       console.log(firebaseResult[i].time); // this returns undefined
       console.log(time);
Sign up to request clarification or add additional context in comments.

Comments

1

It's because you're in the callback of your FirebaseAPI.getLastMessage() call. If you log this (your scope) in it, you'll get something like a FirebaseAPI object or something.

What you can do is the classic var self = this; trick to keep your context stored in a variable accessible through scopes.

This would look like:

for (var i = 0; i < parseResult.length; i++) {

var destination = parseResult[i].attributes.userInfo;

for (var i = 0; i < firebaseResult.length; i++) {

    if (firebaseResult[i].$id == parseResult[i].attributes.facebookID) {


        parseResult[i].attributes.convoID = firebaseResult[i].convoID;

        console.log(firebaseResult[i].time); // this returns the timestamp value
        // Store your context here
        var self = this;
        this.results = firebaseResult[i].time;

        parseResult[i].attributes.lastMessage = FirebaseAPI.getLastMessage(firebaseResult[i]).$loaded()
            .then(function(lastMessage) {

                console.log(firebaseResult[i].time); // this returns undefined
                // Get your values
                console.log(this.results); // this returns your values.

                if (!(0 in lastMessage)) {

                    var returnValue = 'Matched on ' + firebaseResult[i].time;
                } else if (0 in lastMessage) {

                    var returnValue = lastMessage[0].message;
                }

                return returnValue;

            })
            .catch(function(error) {
                console.log("Error:", error);
            })

    }
}

}

I see in your tags that you're using Angularjs, so you could use the $scope object to store your scope variable and easily deal with promises and such.

Hope this helps :)

2 Comments

Thanks very much that's great, I accepted the first answer that worked. This answer explains how to use this and was very informative. Thank you for taking the time :)
No problem :) First answer was indeed also taking in consideration the fact that you are in a loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.