Several AJAX Calls calling same success function not working - javascript

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;
}
});

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

How to send additional parameters to success function in jquery ajax

I have the following Jquery code, I'm trying to display information in $('.cbs-List').HTML(divHTML); based on the region value. But in the success function, I can't read the value for the region, it states that
'data is undefined'
What is the correct form of passing parameters or values to the success function in this case?
$(document).ready(function() {
getSearchResultsREST('LA');
});
function getSearchResultsREST(region) {
var querySA = 'ClientSiteType:ClientPortal* contentclass:STS_Site Region=LA';
var queryDR = 'ClientSiteType:ClientPortal* contentclass:STS_Site Region=EM';
if(region == 'LA') {
var searchURL = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?queryText='" + querySA + "'";
} else {
var searchURL = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?queryText='" + queryDR + "'";
}
$.ajax({
url: searchURL,
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
contentType: "application/json; odata=verbose",
success: SearchResultsOnSuccess(data, region),
error: function(error) {
$('#related-content-results').html(JSON.stringify(error));
}
});
}
function SearchResultsOnSuccess(data, region) {
var results;
var divHTML = '';
if (data.d) {
results = data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
if(results.length == 0) {
$('#related-content-results').html('There is No data for the requested query on ' + _spPageContextInfo.webAbsoluteUrl);
} else {
for (i=0; i<results.length; i++) {
var item = results[i];
var itemCell = item.Cells;
var itemResults = itemCell.results;
// Get values for item result
var _title = getValueByKey("Title", itemResults);
var _path = getValueByKey("Path", itemResults);
divHTML += '<li><a href=' + _path + '>' + _title + '</li>';
}
// Display information based on region.
$('.cbs-List').html(divHTML);
}
}
}
You have 2 problems, and they're both easy to fix.
There's no need to pass region into SearchResultsOnSuccess at all. you can already use it in there because it's defined at a higher scope.
In the object you're passing to $.ajax, you're not setting SearchResultsOnSuccess as a callback, you're calling it.
Change the lines:
success: SearchResultsOnSuccess(data, region) => success: SearchResultsOnSuccess
function SearchResultsOnSuccess(data, region) { => function SearchResultsOnSuccess(data) {
and it should work fine.
Edit:
Here's a basic example of how you need to set this up
function search(region) {
$.ajax({
url: 'example.com',
method: 'GET',
success: successCallback,
});
function successCallback(data) {
console.log(data, region);
}
}
search('LA');
You have to urlencode the value if it contains = or & or whitespace, or non-ASCII characters.
var querySA = encodeURIComponent('ClientSiteType:ClientPortal* contentclass:STS_Site Region=LA');
var queryDR = encodeURIComponent('ClientSiteType:ClientPortal* contentclass:STS_Site Region=EM');
if(region == 'LA') {
var searchURL = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?queryText=" + querySA;
} else {
var searchURL = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?queryText=" + queryDR;
}
And normally you don't have to put your values between apostrophes.
I updated the answer, I hope you will understand me better.
Your problem is NOT the parameter passing IMHO but your server response.
You should either:
turn on the developer tools and check the XHR requests on the network tab, look for the /_api/search/query... requests and examine the response
double check the server side logs/study your search service API documentation how to assemble a proper call
use your favourite REST client and play around your service: send there queries and check the responses and check that it matches with your expectation
last but not least, you can replace your ajax caller with this quick-and-great one:
$.ajax({
url: searchURL,
success: function (response) {
$('#post').html(response.responseText);
},
error: function (jqXHR, exception) {
var msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status == 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status == 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
$('#post').html(msg);
},
});
(of course you should have a <div id="post"><div> somewhere in your page)
Your success function IMHO would get your region if gets called, but it does not, and I hope using one or more of these techniques will help you to see clear.
If you are really sure that you get what you want, you can go furher with passing your second argument, as described here

Ajax request inside another one

I'm making a website for my battlefield 1 clan, on this website i would like to display every player in this clan and also some of their in-game stats.
The player list is stored in a database and i will get the stats from this api
. This means that i will first get the player list from the database using ajax and then loop through them to get the player stats through a second ajax call in that loop.
It all sounds fun and games till i run my code, sometimes not all of the requests succeed and whenever i'm trying to display a displayname it will always show the one from the last call.
This is my code:
$(document).ready(function() {
$.ajax({
url: 'playerlist.php',
method: 'POST',
data: {
playercheck: 1,
},
success: function(response) {
var len = response.length;
for (var i = 0; i < len; i++) {
var psnid = response[i].psnid;
// second ajax
var request = new XMLHttpRequest();
request.open('GET', 'https://battlefieldtracker.com/bf1/api/Stats/BasicStats?platform=2&displayName=' + psnid);
request.setRequestHeader('TRN-Api-Key', '125a7cbe-1bbe-45d4-9f70-3aa838fc7535');
request.onreadystatechange = function() {
if (this.readyState === 4 && this.status == 200) {
console.log('Status:', this.status);
console.log('Headers:', this.getAllResponseHeaders());
console.log('Body:', this.responseText);
var result = JSON.parse(request.responseText);
console.log(result);
$("#userTable").append(result['profile']['displayName']);
}
};
request.send();
// end second
}
},
dataType: "json"
});
});
If you guys could tell me what is causing this and help me find a solution, that would be great.
Thanks in advance!
This is most likely a variable scope issue. In JavaScript, a variable declaration with var is "hoisted" to the top of the containing function. Also, the scope of the variable is the function, NOT the for loop.
So while it looks as if every for loop iteration ought to be creating a completely separate request, instance, that is not what is happening. And by the time the onreadystatechange event fires, your request value has probably changed.
There are two ways to solve this. First, using the new let or const variable declarations of es6 JS, the scope is different. So if you don't need this to work in older browsers, you can just change from var request to let request, and it should work.
If this isn't possible, you'll need to come up with a way to limit the "scope" of your request variable, such as putting your request code in a function, and then calling the function from inside your for loop.
Try this refactorized version:
$(document).ready(function() {
$.ajax({
url: "playerlist.php",
method: "POST",
data: {
playercheck: 1
},
success: function(response) {
getStats(response);
},
dataType: "json"
});
});
function getStats(stats) {
var len = stats.length;
for (var i = 0; i < len; i++) {
getStatInfo(stats[i].psnid);
}
}
function getStatInfo(psnid) {
var request = new XMLHttpRequest();
request.open(
"GET",
"https://battlefieldtracker.com/bf1/api/Stats/BasicStats?platform=2&displayName=" +
psnid
);
request.setRequestHeader(
"TRN-Api-Key",
"125a7cbe-1bbe-45d4-9f70-3aa838fc7535"
);
request.onreadystatechange = function() {
if (this.readyState === 4 && this.status == 200) {
console.log("Status:", this.status);
console.log("Headers:", this.getAllResponseHeaders());
console.log("Body:", this.responseText);
var result = JSON.parse(request.responseText);
console.log(result);
$("#userTable").append(result["profile"]["displayName"]);
}
};
request.send();
}

javascript execute nested ajax call inside a for loop

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.

JavaScript - Prototype Based Programming - this.myFunction is not a function error [duplicate]

This question already has answers here:
how to access the $(this) inside ajax success callback function
(6 answers)
Closed 8 years ago.
I have instantiated the JavaScript object "User". It contains all the necessary for the user management. Even loading and possible AJAX error are managed here.
Below there's a snapshot of this object.
var User = function(uid, ajaxURL) {
this.uid = uid;
this.ajaxURL = ajaxURL;
};
User.prototype = {
loadingShow: function (tag) {
this.tag = (tag) ? tag : '.tab-pane';
$(this.tag + ' .loading').html('<img src="img/template/loading.gif" alt="Loading..." title="Loading...">').fadeIn('fast');
},
//...
};
User.prototype.loadAction = function (rel) {
var utls = new User();
var relAttr = rel;
$.ajax({
type: 'POST',
url: this.ajaxURL + '&id=' + parseInt(this.uid),
cache: true,
dataType: 'json',
data: {
toDo: relAttr
},
beforeSend:function(){
utls.loadingShow('#' + relAttr + '-tab');
},
//...
It works fine but i have just a question, perhaps stupid but I'm facing for first times JavaScript OOP and Prototype-Based-programming.
Why must i create var utls = new User(); for call this utls.loadingShow( and not simply call it by this.loadingShow(?
Using the this property i obtain the error "TypeError: this.loadingShow is not a function".
"Why must i create var utls = new User(); for call this utls.loadingShow( and not simply call it by this.loadingShow(?"
Because this in the callback is set to the jqXHR object.
To override it, you can set the context: property of the $.ajax request to the this value that you want.
$.ajax({
type: 'POST',
url: this.ajaxURL + '&id=' + parseInt(this.uid),
cache: true,
dataType: 'json',
context: this, // <-- set the `this` value of the callbacks
data: {
toDo: relAttr
},
beforeSend:function(){
// v--- now it's correct
this.loadingShow('#' + relAttr + '-tab');
},
success: function(data) {
var art_tmp_str = '';
// Why are you using this? ---v
// $(document).ajaxComplete(function(event, request, settings) {
// v--- now it's correct
this.loadingHide('#' + relAttr + '-tab');
$('#' + relAttr + '-tab').html('');
if(data.success === true) {
// v--- now it's correct
art_tmp_str = this.writeAction(relAttr, data);
$('#' + relAttr + '-tab').append(art_tmp_str);
} else
$('#' + relAttr + '-tab').append('<p>' + data.error + '</p>');
// });
Furthermore, there shouldn't be any need to give a handler to .ajaxComplete() when you're already in a success callback. This should be done before any ajax requests are made if you really want a single behavior applied to all completed requests.

Categories