0
function updateScreenContent() {
    app.map.mapObject.getVisibleRegion(function (bounds) {
        app.ajaxUpdater = $.ajax({
            type: "GET",
            url: "myapi.com/chickens/",
            data: {coordinates: bounds.toUrlValue()},
            dataType: "JSON"
        })
            .done(function (mapItems, status) {
                for (var i = 0; i < mapItems.length; i++) {
                    if (!matchFound) {
                        app.map.mapObject.addMarker({
                            position: new plugin.google.maps.LatLng(mapItems[i].latitude, mapItems[i].longitude),
                            icon: app.map.icons.stop
                        }, function (item) {
                            item.id = mapItems[i].id;
                            app.map.mapContent.push("PUSH ME INTO THE ARRAY!!!!!");
                        });
                    }
                }
            })
    });
}

The above function is called every time the map becomes idle in our application, this could be as much as every 500 milliseconds or longer depending on when the user stops moving the map.

My problem is I can't seem to add any content to my mapContent array inside of the callback where the markers have been successfully added. I know that it's being called because I've put an alert in there and also the markers are successfully added to the map.

Whenever I check the length of mapContent it's always 0. It makes no sense at all! If I push to the array outside of the callback it works.

Any ideas?

EDIT:

addMarker is an asynchronous function. Could this be why?

2
  • What happens if you console.log(app.map.mapContent.length) right after the push? Commented Jun 11, 2014 at 12:38
  • 1
    I suspect it's a closure issue; when that anonymous function calling app.map.mapContent.push executes, the value of i isn't a valid index because JavaScript doesn't (automatically) have block level scoping of variables. Essentially, when that function executes the value of i is its final value of the loop, not the value it had when addMarker was actually called. That results in an error being thrown by the line above the push, and it never being called. Commented Jun 11, 2014 at 12:38

1 Answer 1

1

I suspect it's a closure issue; when that anonymous function calling app.map.mapContent.push executes, the value of i isn't a valid index of the array because JavaScript doesn't (automatically) have block level scoping of variables. Essentially, when that function executes the value of i is its final value of the loop, not the value it had when addMarker was actually called. That results in an error being thrown by the line above the push, since mapItems[i] returns undefined which you can't access an id property on.

You can create a new closure to preserve the value of i for each iteration by using an immediately invoked function expression (IIFE) like so:

(function(i) {
    app.map.mapObject.addMarker({
        position: new plugin.google.maps.LatLng(mapItems[i].latitude, mapItems[i].longitude),
        icon: app.map.icons.stop
    }, function (item) {
        item.id = mapItems[i].id;
        app.map.mapContent.push("PUSH ME INTO THE ARRAY!!!!!");
    });
})(i);
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks so much Anthony. I work with closures often yet I still missed this... most frustrating part of JavaScript!
@jskidd3 Oh, I have a tendency to forget about it, but there's also the let keyword for creating a block-level i variable in your for loop (much easier and more readable than the IIFE closure). I'm not sure what browser compatibility is like these days, but if you have to support more than the latest few versions of IE it probably isn't an option. MDN entry

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.