Hard Light Productions Forums
Off-Topic Discussion => Programming => Topic started by: Ghostavo on January 11, 2010, 01:22:04 pm
-
I'll apologize for what you may see here, and try to excuse myself by saying I've only self-learnt this less than two days ago.
I'm trying to make a website that uses the center of a Google Maps map, does a search in Twitter about posts in the area, and then populates the map with markers.
The code I'm having problems with is the following:
function createMarker(location, name, title, link) {
var marker = new google.maps.Marker({ position: location, map: map });
var infowindow = new google.maps.InfoWindow({ content: "<b>" + name + "</b><br/>" + title + "<br/><a href=\"" + link + "\">Follow more here</a>" });
google.maps.event.addListener(marker, "click", function () {
infowindow.open(map, marker);
});
return marker;
}
function update() {
if (request.readyState == 4) // 0 = uninitialized -- 1 = loading -- 2 = loaded -- 3 = interactive -- 4 = complete
{
if (request.status == 200) // 200 = OK
{
try {
var xmlDoc = request.responseXML;
var x = xmlDoc.getElementsByTagName("entry");
for (i = 0; i < x.length; i++) {
var name = x[i].getElementsByTagName("name")[0].childNodes[0].nodeValue;
var title = x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
var link = x[i].getElementsByTagName("uri")[0].childNodes[0].nodeValue;
var locationStr = x[i].getElementsByTagName("location")[0].childNodes[0].nodeValue;
if (locationStr.indexOf("T:") == -1) {
if (geocoder) {
geocoder.geocode({ 'address': locationStr }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// coloca um marcador e um comentário associado
var location = new google.maps.LatLng(results[0].geometry.location.lat() + (0.004 - 0.008 * Math.random()), results[0].geometry.location.lng() + (0.004 - 0.008 * Math.random())); // espalha os pontos por uma localidade
createMarker(location, name, title, link);
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
}
else {
var location = new google.maps.LatLng(locationStr.slice(locationStr.indexOf(":") + 1, locationStr.indexOf(",")), locationStr.substr(locationStr.indexOf(",") + 1));
// coloca um marcador e um comentário associado
createMarker(location, name, title, link);
}
}
}
catch (e) {
alert("Problem parsing XML");
}
}
else {
alert("Twitter hates you!");
}
}
}
The below function calls the above function each time it needs to create a marker and infowindow and passes the necessary arguments. What happens is when the infowindow is created, the arguments passed are the last value of the variables name, title, etc... The end result of this is that the map is populated by various markers (meaning the location argument was diferent each time), each with identical infowindows (and all the other arguments seem to be the same). What I can't see is why and how to deal with this.
Any help?
[attachment deleted by admin]
-
Got a link to it active somewhere? It's infinitely easier to debug these things if I can trace with firebug.
-
I'm afraid I'm testing it locally. I haven't got a server or anything of the sort.
-
you could attach it
-
I've posted the complete code. Faint-hearted beware.
-
Final Edit: Fix Attached.
Please note changes:
code = 200 changed to code = 200 or code = 0, as local files return status 0.
location changed to google:location to match xml file supplied.
Geocode creation and callback enclosure. moved into a seperate function
Here's what was going on: In your update function, you had a tight loop (for (i = 0; i < x.length; i++)). The geocoder call back enclosure was being created in this loop, and the
variables used in the callback were local in scope to the loop. This means that the callback uses the value of the variable in the loop at the time it gets called back. Since geocoder is
asynchronous, in each iteration of the loop, it would create the callback, send the request, and move on - changing all the variables. It's a tight loop, and doesn't do much else, so it
would be moved through very, very fast. By the time the first geocoder request finished and called back, the loop was finished - which means the variables had been changed to the final
value they would've had in the loop. Those variables were used to create the infowindow - the location was determined by the request, which was sent at the appropriate time.
The end result - every marker's callback was using the final values of name, title, link and locationStr.
By moving the creation of the callback to a seperate function, the scope of the enclosure is changed. The variables used are the ones passed into the function, and those do not change after
the function is called.
Lesson: Javascript closure scopes are complicated, especially when matched up with Asynchronous code.
[attachment deleted by admin]
-
Thanks.
I see I need to pay more attention to when the callback functions are actually called back. :D