I’m using the Google Maps API to plot several points on a map. However, in the click event function below, i is always set to 4, i.e. its value after iterating the loop:
// note these are actual addresses in the real page
var addresses = new Array( "addr 1", "addr 2", "addr 3", "addr 4" );
for (var i = 0; i < addresses.length; i++) {
geocoder.getLatLng(addresses[i], function(point) {
if (point) {
var marker = new GMarker(point);
map.addOverlay(marker);
map.setCenter(point, 13);
GEvent.addListener(marker, "click", function() {
// here, i=4
marker.openInfoWindowHtml("Address: <b>" + addresses[i] + "</b>");
});
}
});
}
So when the marker displays it’s using addresses[4] which is undefined. How do I pass the correct value of i to the function?
You need to generate an anonymous function during the current iteration, the following should fix it:
B// note these are actual addresses in the real page
var addresses = new Array( “addr 1”, “addr 2”, “addr 3”, “addr 4” );
for (var i = 0; i < addresses.length; i++) {
geocoder.getLatLng(addresses[i], function(point) {
if (point) {
var marker = new GMarker(point);
map.addOverlay(marker);
map.setCenter(point, 13);
}
Further Clarification
The
getLatLngmethod provided by Google uses an ajax call to get the lat and long for a specific address. Since this is an asynchronous call and is not part of the current thread, a callback function is required which is called on completion of the ajax request. This is the anonymous function you specify as the second parameter of the function.Now, whilst the ajax requests are being made, your code continues to run, increasing the value of
ieach time the loop iterates over the array. By the time your first ajax call returns, the loop has already increased to the length of the addresses array (4), so when the your callback function runs you’re retrieving the in-scope variableiafter it has been increased by the loop.With the fix I wrote, you’re creating an anonymous function that takes a single argument –
current– and returns the previous anonymous function with theivariable replaced with thecurrentvariable. This function is invoked right away, before the next iteration of the loop, with theivariable as it’s first parameter. This creates a closure for which the current value ofiis stored in thecurrentvariable at the time the function is called. When we refer to thecurrentvariable later, we’re getting the stored value ofi.I’m not really very good at explaining these sort of things, probably because my understanding of it isn’t quite as good as the js Gods. Better to read some more info on javascript closures.