javascript execute nested ajax call inside a for loop - javascript

So, I have two code snippets - both of them are executing without errors. Both are meant to do the same thing - loop through a list of words and look up documents these words appear in (SOLR), then pull paragraphs where these words appear from each document. However they don't return the desired result. The first one skips over the nested ajax call (the one inside the for each loop) and if runs the ajax call at all, it's after the main (parent) loop already finished. The second one only works properly if there is an alert there. If the user acknowledges the alert, then the second loop executes correctly. Without the alert, the second loop gets skipped. Can anyone shed some light at what is wrong here. I've tried ajax {complete:...} and ajax{}.done but they didn't work either.
Here is the first snippet:
for (var m = 0; m < definitions.length; m++ ) {
var url = pathtomyfile;
var doctitle, docname, docs;
var htmlBody, pHtml, fullHTML;
$.ajax({
url: url,
async: false,
dataType: 'json',
success: function (result){
docs = result.response.docs;
},
complete: function () {
$(docs).each (function (){
var doctitle = this.dc_title_str.toString().replace (/(\.html|\.htm)/, '');
var docname = filePathToUrl (this.resourcename.toString ());
var url = decodeURIComponent (docname);
$.ajax({
url: url,
async: false,
dataType: 'html',
success: function (resp){
fullHTML = resp.toString();
htmlBody = fullHTML.split (/<body>/)[1].split (/<\/body>/)[0];
htmlBody = htmlBody.replace (/\s/g, " ").replace (/ /g, " ").replace (/(<a id="x\d+?")\/>/g, "$1></a>");
var pHtml = $(htmlBody).find("#id").parent();
pHtml = $(pHtml).wrap('<p/>').parent().html();
pHtml = pHtml.replace (/\<a id/g, "#s#").replace (/<\/a>/g, "#e#").replace (new RegExp ("\\b(" + en_word.replace (/\s/g, "(<[^<]+?>| )*")+"(s|ed|ing|es)*)\\b", "ig"), "<span style='background-color:yellow'>$1</span>").replace (/#s#/g, "<a id").replace (/#e#/g, "<\/a>");
hsnip += "<p><b><i>From " + doctitle + ":</i></b></p> " + pHtml;
}
});
})
}
});
}
this is the second snippet:
for (var m = 0; m < definitions.length; m++ ) {
var url = pathtomyfile;
var doctitle, docname, docs;
var htmlBody, pHtml, fullHTML;
$.ajax({
url: url,
async: false,
dataType: 'json',
success: function (result){
docs = result.response.docs;
}
});
alert ('ok');
for (var b = 0; b < docs.length; b ++) {
doctitle = docs[b].dc_title_str.toString().replace (/(\.html|\.htm)/, '');
docname = filePathToUrl (docs[b].resourcename.toString ());
var rawFile = new XMLHttpRequest ();
docname = decodeURIComponent (docname);
rawFile.open ("GET", docname, false);
rawFile.onreadystatechange = function () {
if (rawFile.readyState === 4 && (rawFile.status === 200 || rawFile.status === 0)) {
fullHTML = rawFile.responseText.toString();
htmlBody = fullHTML.split (/<body>/)[1].split (/<\/body>/)[0];
var pHtml = $(htmlBody).find("#id").parent();
pHtml = $(pHtml).wrap('<p/>').parent().html();
hsnip += "<p><b><i>From " + doctitle + ":</i></b></p> " + pHtml;
}
}
rawFile.send (null);
}
}

This sounds like an async problem, is not the best idea to make AJAX calls in a loop, you can replicate a loop with recursivity though, have the function only make one call, and call the function again when each call is finished, and add a breakpoint with an if that checks if you're finished.

Related

Why is my code not waiting for the promises to complete?

I have the following code making multiple AJAX calls (by calling ExecuteServiceMethod) in an jquery "each" loop. I'd like to wait for all the calls to complete before calling the "__doPostBack", but it doesn't seem to be working and the postback gets called before all the ajax calls return.
Here's the calling code:
$("table[id*=ChangeAllGridView]").on("hide.bs.dropdown", ".dropdown.bootstrap-select", function (event) {
var LotID = '<%=Session[ID + "EditedLot"]%>';
var SplitsList = $(event.target).children("button.dropdown-toggle").attr("title");
var SplitsArray = $(event.target).children("select").val();
var promises = [];
$(".selectpicker[id*=SplitDropDown]").not("[id*=SplitDropDown_All]").each(function () {
$(this).selectpicker("val", SplitsArray);
var WID = $(this).attr("id").split("_")[3];
var a = ExecuteServiceMethod("LotEditorWebService.asmx", "UpdateWaferSplits", ["LotID", LotID, "WID", WID, "SplitsList", SplitsList], function () { });
promises.push(a);
});
Promise.all(promises).then(function () {
__doPostBack($(event.target).attr('id'), '');
});
});
And here's the ExecuteServerMethod routine making the AJAX call:
function ExecuteServiceMethod(page, fn, paramArray, successFn, errorFn) {
var paramList = '';
if (paramArray.length > 0) {
for (var i = 0; i < paramArray.length; i += 2) {
if (paramList.length > 0) paramList += ',';
paramList += '"' + paramArray[i] + '":"' + paramArray[i + 1] + '"';
}
}
paramList = '{' + paramList + '}';
return $.ajax({
type: "POST",
url: page + "/" + fn,
contentType: "application/json; charset=utf-8",
data: paramList,
dataType: "json",
success: successFn,
error: errorFn
});
}
I've tried a number of iterations of this, including putting a "new Promise()" statement around the AJAX call and returning that, but nothing seems to help.
Would appreciate your help on this.
Thanks.
try wrapping like this: Promise.resolve($.ajax(...))
edit: you can also try removing the success and error callbacks in the ajax function
edit edit: also try catching any errors on your Promise.all

Several AJAX Calls calling same success function not working

I have a question to the behaviour of this AJAX call shown below which I dont understand.
var checkBoxes = document.getElementsByName("newInclCheckBox");
for(var i = 0; i<checkBoxes.length; i++
{
if(checkBoxes[i].checked)
{
var name2 = getTabKeyFromDescription(checkBoxes[i].value);
var tablenr2 = checkBoxes[i].getAttribute("data-tablenr");
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function()
{
if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
document.getElementById('newIncl_LogBox').innerHTML += xmlhttp.responseText;
}
}
xmlhttp.open("GET", "../PHPScripts/getInclusions.php?q=add&name1=" + name1 + "&tablenr1=" + tablenr1 + "&name2=" + name2 + "&tablenr2=" + tablenr2, true);
xmlhttp.send();
}
}
As you can see, the AJAX Call is inside a for-loop and gets called several times while looping through checkBoxes.
The PHP-Skript getInclusions.php completes each request successfully, but somehow only the last xmlhttp.responseText gets written in my LogBox.
I would understand this behaviour if i had written
document.getElementById('newIncl_LogBox').innerHTML = xmlhttp.responseText;
(without += Operator).
Why is the writing in the logbox not as expected? Any help is greatly appreciated!
You can call ajax synchronously in for loop then it will execute one by one like that and use this code in your code as usual.
This is syncronous ajax call example.
urllink="../PHPScripts/getInclusions.php?q=add&name1=" + name1 + "&tablenr1=" + tablenr1 + "&name2=" + name2 + "&tablenr2=" + tablenr2;
$.ajax({
async: "false",
type: "GET",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: urllink,
success: function(jsonData) {
alert("jsonData =" + jsonData);
return jsonData;
}
});

Append Order - jQuery

I am trying to get the string to order by how it is displayed (red,blue,orange,black). For some reason, it will append the order randomly. For Example: it would output (blue,orange,red,black). Any help would be great. Thanks.
var tCookie = "red,blue,orange,black";
var Cookies = tCookie.split(',');
if (Cookies) {
for (var i = 1; i <= Cookies.length; i++) {
var dataString = "TabId="+Cookies[i]+"";
$.ajax({
type: "POST",
url: "includes/tab.php",
data: dataString,
cache: false,
success: function(html){
$("#Dynamic_Tab").append(html).children(':last').hide().fadeIn("fast");
}
});
}
}
You could have a list of requests and responses, and start appending when all are done, so that the order is always correct:
var deferreds = [],
results = [];
for (var i = 1; i <= Cookies.length; i++) {
(function(i) { // to freeze i
var dataString = "TabId="+Cookies[i]+"";
deferreds.push($.ajax({
type: "POST",
url: "includes/tab.php",
data: dataString,
cache: false,
success: function(html){
results[i] = html; // insert at the synchronous position
}
}));
})(i);
}
$.when.apply($, deferreds).then(function() {
$.each(results, function(i, html) {
$("#Dynamic_Tab").append(html).children(':last').hide().fadeIn("fast");
});
});
You can use deferred objects here to only append the HTML after all of the AJAX requests come back:
//create array to store XHR objects that will resolve when the AJAX requests return
//also create an object to store the AJAX responses
var jqXHRs = [],
responses = {};
//iterate through each of the cookie indexes
$.each(cookies, function (index, value) {
//create the dataString and cache the value of this index so it can be used in the success callback for the AJAX request associated with this index
var dataString = "TabId=" + value,
thisValue = value;
//store an empty string in the output variable for the current index, this keeps it's place in-line
responses[thisValue] = '';
//do the AJAX request and store it's XHR object in the array with the rest
jqXHRs[jqXHRs.length] = $.ajax({
type : "POST",
url : "includes/tab.php",
data : dataString,
cache : false,
success : function (html) {
//now that the AJAX request has returned successfully, add the returned HTML to the output variable for this index
responses[thisValue] = html;
}
});
});
//wait for all of the XHR objects to resolve then add all the HTML to the DOM
$.when(jqXHRs).then(function () {
//all of the AJAX requests have come back and you can now add stuff to the DOM
var $element = $("#Dynamic_Tab");
$.each(responses, function (index, value) {
$element.append(value).children(':last').hide().delay(index * 250).fadeIn(250);
}
});
The .delay() is so that each new row will fade in, in order.

Why is Javascript output being held back in Google Chrome?

I have javascript/jquery code which fetches info and updates it into the database with a mixture of while/for loops. While fetching, I have a div which shows a current progress log of whats going on. In Firefox, as the script is running it updates the div at the same time as it should. In Google Chrome, it runs the entire loop, holding back the log, and only outputs it until the script is finished running. Anyone have any idea why this is happening?
Here is my code:
$(document).ready(function() {
add_text("test");
var array_length = num_sets;
for(var i = 0; i < array_length; i = i + 1) {
var setId = sets[i]['id'];
var setName = sets[i]['name'];
var setLinkName = sets[i]['link'];
var setNumCards = sets[i]['num_cards'];
add_text("Beginning to fetch set \"" + setName + "\"");
add_text("Found " + setNumCards + " total cards.");
while(ii < setNumCards) {
var card_name = sets[i]['cards'][ii]['name'];
var card_link = sets[i]['cards'][ii]['link'];
add_text("Fetching card " + sets[i]['cards'][ii]['name']);
fetch_card(sets[i]['cards'][ii]['link'], setId);
}
}
});
add_text function:
function add_text(text) {
$("#status_text").append("<br />" + text);
}
fetch_card function:
function fetch_card(card_link, set_id)
{
$.ajax({
url: "fetch_card.php?link=" + card_link + "&set_id=" + set_id,
context: document.body,
async: false,
success: function(){
ii = ii + 1;
}
});
}
You are using synchronous ajax calls (which are generally not very desirable). The browser can block all activity until that ajax call completes. Whether or not the browser updates the screen during a synchronous ajax call is up to the browser.
Your code would be much better if it was rewritten to use asychronous ajax only. It takes a little more work to structure your code properly to work with asynchronous ajax calls, but the browser remains completely responsive during the asynchronous ajax calls.
I'm not entirely sure how you were using the ii variable in your original implementation (as it wasn't declared or initialized in the code you included), but this is the general structure you could use. It uses the traditional for loop to collect all the data you wanted in an array, then calls the ajax function one a time on that data. It isn't clear to me how you're actually doing anything with the returned ajax info, but perhaps that just isn't something you included here:
$(document).ready(function() {
add_text("test");
var array_length = num_sets;
var fetchData = [];
var fetchIndex = 0;
for(var i = 0; i < array_length; i++) {
var setId = sets[i]['id'];
var setName = sets[i]['name'];
var setLinkName = sets[i]['link'];
var setNumCards = sets[i]['num_cards'];
add_text("Beginning to fetch set \"" + setName + "\"");
add_text("Found " + setNumCards + " total cards.");
for (var ii = 0; ii < setNumCards; ii++) {
var card_name = sets[i]['cards'][ii]['name'];
var card_link = sets[i]['cards'][ii]['link'];
add_text("Fetching card " + sets[i]['cards'][ii]['name']);
fetchData.push({link: sets[i]['cards'][ii]['link'], id: setId});
}
}
function next() {
if (fetchIndex < fetchData.length) {
fetch_card(fetchData[fetchIndex].link, fetchData[fetchIndex].id, next);
fetchIndex++;
}
}
function fetch_card(card_link, set_id, successFn) {
$.ajax({
url: "fetch_card.php?link=" + card_link + "&set_id=" + set_id,
context: document.body,
async: true,
success: successFn
});
}
next();
});

Post with ajax-jquery send blank space when the sentence have +

I am sending a request by post using jquery ajax, but some of the words i send have + to join words like: HTA+HIPERAQUITISM+DBLR, the php recieve HTA HIPERAQUITISM DBLR changing the + by blank spaces, i post the code below. help!
function getItemInfo(itemName, itemField, itemComparative, itemTable){
var result = "";
var nombreItem = itemName;
var campoItem = itemField;
var comparativeItem = itemComparative;
var tableItem = itemTable;
$.ajax({
type: 'POST',
async: false,
url: 'modules/medicos/controller.php?fun=consul_item&nombre_item=consul_item'+
'&nombre_item='+nombreItem+
'&campo='+campoItem+
'&comparador='+comparativeItem+
'&tabla='+tableItem,
success: function(data) {
result = data.toString();
},
failure: function() {
result = "";
}
});
return result;
}//end function
This is because in a URL + means space.
You'll need to URL encode the data first before adding it to the query string.
You can use the encodeURIComponent() function to encode your value before adding it to the query string.
Once your PHP code picks it up you can then decode the value with the urldecode function
So your code should update to something like this:
url: 'modules/medicos/controller.php?fun=consul_item&nombre_item=consul_item'+
'&nombre_item='+encodeURIComponent(nombreItem)+
'&campo='+encodeURIComponent(campoItem)+
'&comparador='+encodeURIComponent(comparativeItem)+
'&tabla='+encodeURIComponent(tableItem),
Your code seems to be correct. You are passing those variables one by one (nombreItem, campoItem, comparativeItem and tableItem). So I don't really understand what you say is not working.
A suggestion to make passing data easier:
$.ajax({
type: 'POST',
async: false,
url: 'modules/medicos/controller.php',
data : ({ fun : consul_item,
nombre_item : nombreItem,
campo : campoItem,
comparador : comparativeItem,
tabla : tableItem }),
success: function(data) {
result = data;
},
failure: function() {
result = "";
}
});
If you want to pass all your info as one textual string you should do:
...
data: ({ test : consul_item + '+' + nombreItem + '+' + campoItem + '+' + comparativeItem + '+' + tableItem }),
...

Categories