Javascript scope error
I am currently working on a Google Maps project and am implementing a search function. In my search function, I try to have content on the side, the list that the creators who just added to the map match each room. However, when assembling this line, I am running into an issue where my variable side_bar_html
will not be outputted unless I first alert the data.
Here is my searchMap function. The variable is declared as such:var side_bar_html = "";
function searchMap(term, map) {
closeSearch();
searchCount = 0;
searchMarkers = [];
var request = GXmlHttp.create();
request.open("GET", "admin/search.php?s=" + term, true);
request.onreadystatechange = function() {
if (request.readyState == 4) {
var xmlDoc = GXml.parse(request.responseText);
var points = xmlDoc.documentElement.getElementsByTagName("point");
var polygonsToShow = [];
for (var i = 0; i < points.length; i++) {
var lat = parseFloat(points[i].getAttribute("lat"));
var lng = parseFloat(points[i].getAttribute("lng"));
var pid = points[i].getAttribute("id");
for(var j = 0; j < polygons.length; j++) {
if(polygons[j].vt_bid == pid) {
polygonsToShow.push(j);
}
}
var point = new GLatLng(lat,lng);
var pname = points[i].getAttribute("name");
var curMarker = createSearchMarker(point, pid, pname,getLetter(i));
map.addOverlay(curMarker);
}
//olays.buildings.checked = false; : Figure out some way to uncheck the buildings overlay checkbox?
for(var k = 0; k < polygons.length; k++) {
polygons[k].hide();
}
for(var l = 0; l < polygonsToShow.length; l++){
polygons[polygonsToShow[l]].show();
}
}
}
request.send(null);
alert(side_bar_html); //side_bar_html will be empty unless I alert the variable
searchResults = new HtmlControl('<div style="background-color:white; border:solid 1px grey; padding:2ex; overflow:auto; width:125px; margin:1px; font-size:14px;"><img align="right" style="cursor: pointer;" src="http://www.thebort.com/maps/images/close.gif" onclick="closeSearch()"><strong>Search</strong><br/>' + side_bar_html + '</div>', {selectable:true});
map.addControl(searchResults, new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(20, 70)));
}
And the function to create a search marker:
function createSearchMarker(point, id, pname, letIcon) {
var marker = new GMarker(point,letIcon);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml('<a href="#" onclick=\'tb_show("' + pname + '","admin/get_info.php?b=' + id + '&KeepThis=true&TB_iframe=true&height=400&width=600",false); return false;\'>' + pname + '</a>');
});
side_bar_html = side_bar_html + '<a href="javascript:clickSearch(' + searchCount + ')">' + String.fromCharCode("A".charCodeAt(0) + searchCount) + ': ' + pname + '</a><br>';
marker.vt_id = id;
searchMarkers.push(marker);
searchCount++;
return marker;
}
I would like to keep the code for this project at least for now, so if anything needs to be outlined, please let me know. Thank!
source to share
So my understanding of your problem is what side_bar_html
is being set during a function call onreadystatechange
, but you don't see it set unless you warn it.
Here's what's probably going on: The Ajax request takes a while. When you call it req.send(null)
, it will unsubscribe the request, but your function onreadystatechange
will not be called until after some time your web browser makes a request and returns a response.
So when you try to use the value right away side_bar_html
, it doesn't work because the answer hasn't returned yet. However, when you alert about a value, the time it takes to execute the alert gives the browser time to receive a response and set the value side_bar_html
accordingly.
The main problem is that Ajax is asynchronous (which is where A comes from) and you are trying to use it synchronously (which means that you are assuming things will happen in a specific order). Your best bet is to put the code that side_bar_html
your function uses onreadystatechange
so that it doesn't get used to before installing it.
source to share
add the code below to the end of your onreadystatechange function (inside an if statement checking the value 4). eg:
request.onreadystatechange = function() {
if (request.readyState == 4) {
var xmlDoc = GXml.parse(request.responseText);
var points = xmlDoc.documentElement.getElementsByTagName("point");
var polygonsToShow = [];
for (var i = 0; i < points.length; i++) {
var lat = parseFloat(points[i].getAttribute("lat"));
var lng = parseFloat(points[i].getAttribute("lng"));
var pid = points[i].getAttribute("id");
for(var j = 0; j < polygons.length; j++) {
if(polygons[j].vt_bid == pid) {
polygonsToShow.push(j);
}
}
var point = new GLatLng(lat,lng);
var pname = points[i].getAttribute("name");
var curMarker = createSearchMarker(point, pid, pname,getLetter(i));
map.addOverlay(curMarker);
}
//olays.buildings.checked = false; : Figure out some way to uncheck the buildings overlay checkbox?
for(var k = 0; k < polygons.length; k++) {
polygons[k].hide();
}
for(var l = 0; l < polygonsToShow.length; l++){
polygons[polygonsToShow[l]].show();
}
searchResults = new HtmlControl('<div style="background-color:white; border:solid 1px grey; padding:2ex; overflow:auto; width:125px; margin:1px; font-size:14px;"><img align="right" style="cursor: pointer;" src="http://www.thebort.com/maps/images/close.gif" onclick="closeSearch()"><strong>Search</strong><br/>' + side_bar_html + '</div>', {selectable:true});
map.addControl(searchResults, new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(20, 70)));
}
source to share