ok i have an ajax call that recives a json object.
the idea of whatn i am trying to do is get a list of all records flagged, and geocode them do a reverse lookup and save back to the database, but as a batch
I want to loop through the data and then perform an additional ajax call (which will geocode the data) and then perform another ajax call to save to the database.
the problem is in my for loop everything runs too quickly and there is no pause between the calls and the browser crashes, or the save to database function adds the wrong data.
$('#geo_batch').click(function (){
var ajax_load = "<label><img src='/images/icons/loadinfo.gif' alt='saving location...' /> Loading data...</label>";
$("#batch_detail").html(ajax_load);
$('#batch_buttons').hide();
saveall = true;
var form = $("form"); //Grab the form element from the DOM
//alert(form.serialize());
var mydata = form.serialize();
$.ajax({
type: "POST",
url: 'geo_getupdate_list.php',
data: mydata,
dataType: 'json',
success: function(dat) {
processbatch(dat);// process the returned data
},
error: function(dat) { //Triggered if an error communicating with server
//alert('fail');
$("#batch_detail").html('<label>There was an error: '+dat+'<label>');
$('#batch_buttons').show();
}
});
return false; //Ignore the default behavior of the button click
});
the process data function
function processbatch(dat){
// Cache the batch_detail element
$("#batch_detail").html('<label>Locations have been retrieved:<br>' + dat + '<label>');
$('#batch_buttons').show();
var count = dat.location.length - 1;
for(i=0; i < count; i++){
$('#batch_detail').append('<li>address: ' + dat.location[i].geoaddr_mdt + 'flag: ' + dat.location[i].flag_mdt+'</li>');
$('#id_mdt').val(dat.location[i].id_mdt);
$('#entrytype').val(dat.location[i].idedt_mdt);
$('#name').val(dat.location[i].name_mdt);
$('#geo_addr').val(dat.location[i].geoaddr_mdt);
$('#telephone').val(dat.location[i].telephone_mdt);
$('#email').val(dat.location[i].email_mdt);
$('#geo_detail').val(dat.location[i].displayaddr_mdt);
$('#website').val(dat.location[i].website_mdt);
//$('#active').val(dat.location[i].active_mdt);
var address = dat.location[i].geoaddr_mdt;
// if address is not empty
if(address != '') {
address_lookup(address, region, 'update');
};
};
};
address lookup function
function address_lookup(address, region, savetype) {
// set default region
if(region==null || region == '') {
region = 'uk';
};
// address not empty
if(address != '') {
//clear existing markers<br />
if(savetype == 'save'){
removemarkers();
};
$('#geo_detail').html('<label>Geocoding address...</label>');
// lookup the address
geocoder.geocode( {'address':address,'region':region}, function(results, status) {
// if the address was found
if(status == google.maps.GeocoderStatus.OK) {
$str = '<label>Geocode Successful<br> Lattitude: '+results[0].geometry.location.lat()+' Longitude: '+results[0].geometry.location.lng()+'<br> The address is displayed below and will be stored in the database.<br> If the address is incorrect you may edit it before saving the location to the database.<br>If the marker is in the wrong location you may drag it to where you believe it should be.</label>';
$('#geo_detail').html($str);
// insert lat/long into form
$('#lat').val(results[0].geometry.location.lat());
$('#lng').val(results[0].geometry.location.lng());
// create new lat/long object
latlng = new google.maps.LatLng(results[0].geometry.location.lat(),results[0].geometry.location.lng());
$('#disp_addr').val(address);
$('#form_buttons').show();
$('#detail_address').show();
//reverselookup(results[0].geometry.location.lat(), results[0].geometry.location.lng());
// set zoom option
map.setZoom(15);
// center the map on the new location
map.setCenter(results[0].geometry.location);
createMarker(map, latlng, true, false);
if(savetype ='update'){
savedata('update');
};
if(savedata='save'){
savedata('save');
};
} else {
// display error
$('#geo_detail').append('<label>Geocoder failed to retrieve address: '+status+'</label>');
$('#disp_addr').val($('#geo_addr').val());
};
});
};
};
EDIT in reply to Zacks 1st comment—-
i want to show each result as it is being processed, then output the result to the geo_detail div so there is a list of the processed record and associated error messages that are returned, idealy i would like the option to have the user review each record as it is processed, so the loop gets paused until the user clciks the save button, which would perhaps set a global var to true which my loop would check and wait for, b ut to start with i need some kind of pause so that the various ajax calls have time to execute before processing the next record.
END EDIT——————————
any ideas or pointers would be much appreciated
thanks
I don’t think “everything runs too quickly” is an accurate diagnosis of whatever problem you are having.
One thing I see is that you have ajax calls being initiated from the success fn of other ajax calls. I don’t know if the ajax lib is re-entrant. You may want to avoid that.
The way I would do it is to introduce asynchrony into the mix. Use
setTimeout()to invoke yourprocessbatch()function. It will then run asynchronously, with respect to the first ajax call.Also consider using asynchrony to invoke the goecoder, as well. Only send a new geocoder request after all other geocoder requests have completed. The way you do it, you send them all at once. (Maybe this is what you mean by “everything runs too quickly”).
The way to do this: accept into your address_lookup fn an array of address objects and an index. Invoke the geocoder on the i’th address. Then when the call completes (success or failure), increment the index, and use setTimeout to invoke address_lookup again.
This way you always have at most one outstanding call to the geocoder.
It looks something like this in code:
EDIT
ps: I recommend you fixup your fn naming to use camelCase and verbNoun naming. So,
processBatch()andlookupAddress(), rather thanprocessbatch()andaddress_lookup().EDIT
Here’s how to think about it: when you invoke an ajax call, you’re telling the browser to send out an HTTP request. Normally at the time you invoke the call you pass a “success” function that gets invoked for you, when the HTTP Response is received. As you know from using the browser, the response can arrive quickly, or not so quickly. When you invoke ajax calls in a loop, you’re telling the browser to send out N simultaneous HTTP requests. Not necessarily what you want.
What I’m suggesting here is to invoke one AJAX call at a time (to the geocoder, for example) and only invoke the next one from the success fn – that is to say, AFTER the response is received from the first one. Also, if you do it using
setTimeout(), you will avoid deep fn nesting.