0

I've been playing around with JavaScript and there's something I don't quite understand. I have this piece of code here:

$.getJSON('data.json', function(obj) {

    for( var p in obj.List )
    {               
        datas['id'] = obj.List[p].ListingId;
        datas['area'] = area;

        //console.log(datas);

        var geocoder = new google.maps.Geocoder();              
        geocoder.geocode( { 'address': datas['area'] }, function(results,status)
        {

            if(status == google.maps.GeocoderStatus.OK)
            {
                var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);

                datas['latlng'] = latlng;

                //console.log(datas);                       

            }                               
        });
     }      
});

Ok, now suppose the for loop runs 3 times. If we uncomment the first "console.log(datas)" line and run the page, in the console we see 3 "datas" objects with their own "id" and "area". If I comment that first "console.log(datas)" and uncomment the second "console.log(datas)" in the geocode callback, when I run the code, all 3 "datas" objects are exactly the same in terms of "id", "area", and "latlng". Whereas I expected the 3 "datas" objects would be different with their own latlngs.

Any ideas?

3 Answers 3

1

When is the function you pass to the geocoder.geocode function run? If it's not being run immediately then the for loop will run through all three times before the geocode function is run. That means that datas['id'] and datas['area'] will have been set to the last iteration of the loop... in which case you need to capture the datas array inside a closure for the geocode function.

In which case you'd need something like:

$.getJSON('data.json', function(obj) {

    for( var p in obj.List )
    {               
        datas['id'] = obj.List[p].ListingId;
        datas['area'] = area;

        //console.log(datas);

        var geocoder = new google.maps.Geocoder();              
        geocoder.geocode( { 'address': datas['area'] }, function(datas){ return function(results,status)
        {

            if(status == google.maps.GeocoderStatus.OK)
            {
                var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);

                datas['latlng'] = latlng;

                //console.log(datas);                       

            }                               
        }}(datas));
     }      
});

This prevents the datas variable as used by the anonymous function being updated by the for loop.

Sign up to request clarification or add additional context in comments.

Comments

1

I think this is a scope problem. By the time that last console.log runs the p variable will already refer to the last obj. You need to capture p in a new scope.

for( var p in obj.List ) { 

  (function(p) {

    datas['id'] = obj.List[p].ListingId;
    datas['area'] = area;

    geocoder.geocode( { 'address': datas['area'] }, function(results,status) {
      ...
    });

  }(p));

}

4 Comments

Great - that fixed it! I still don't quite understand however why this fixes it. Could you elaborate on this a bit?
When the callback in geocoder runs, the loop has already finished thus the p variable will only refer to the last item that's why you need to keep a reference to p. I found this link with more info zef.me/2843/javascript-the-scope-pitfall, you can also look for "closures javascript" on google, you'll find lots of useful stuff.
I have to admit, I'm a little confused by this as well, since p isn't used inside the callback. Is this by any chance turning datas into a local variable of the function scope? If that's the case then you don't need the p argument at all...
Ah I think I understand now. I didn't quite realize that the geocoder ran after that whole loop was finished (I thought the async call to it was immediate). Thanks both of you guys
0

I think datas has to be declared as a global array? Has it?

1 Comment

I did make it global at one point but I don't recall it fixed it.

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.