complete callback is not being called for async.parallel - javascript

I need to make an api call for 100 rows to populate description (which I prefer to do it in parallel). However some of rows might not have description in this case api will return 404. I need to show a warning message when there are a row or rows without description and remove those rows from modal data which means I need a complete callback or done callback. However the completeCallback is not being called and I "think" it's because some of rows doesn't have description.
Could you please tell me how to achieve that?
Here is my code:
function getDescription(processedData) {
$.ajax({
url: baseApiUrl + '/Summary?id=' + processedData.id,
type: 'GET',
dataType: 'json',
contentType: 'application/json',
success: function (data) {
processedData.SummaryDescription = data;
},
error: function (xhr, status, e) {
if(xhr.statusCode === 404){
processedData.SummaryDescription = '';
}else{
}
}
});
};
//Below line is in a look
parallelCallArray.push(getDescription.bind(null, processedData));
//Below line is out of loop
Async.parallel(parallelCallArray, function(err, result){
console.log('all calls completed...');
});

You're missing the callback parameter of your function(s) that are being executed in parallel. If you don't execute the callback, async will assume your functions haven't finished yet. Try something like this:
function getDescription(processedData, cb) {
$.ajax({
url: baseApiUrl + '/Summary?id=' + processedData.id,
type: 'GET',
dataType: 'json',
contentType: 'application/json',
success: function (data) {
processedData.SummaryDescription = data;
cb();
},
error: function (xhr, status, e) {
if (xhr.statusCode === 404) {
processedData.SummaryDescription = '';
} else {
}
cb(new Error(e));
}
});
}

Related

Handing value into Success function from AJAX Call

G'day all,
I'm trying to pass a value through to a Success var from the original AJAX call.
Here's some code :
function isJobComplete(jobGUID) {
var data = { "pJobGUID": jobGUID };
var url = '/DataService.asmx/isJobComplete';
var success = function (response, jobGUID) {
if (response.d) {
//The job is complete. Update to complete
setJobComplete(jobGUID);
}
};
var error = function (response) {
jAlert('isJobComplete failed.\n' + response.d);
};
sendAjax(data, url, success, error);
}
function sendAjax(data, url, success, error) {
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: success,
error: error || function (response) {
jAlert(response.d);
}
});
}
When the isJobComplete function runs, it has the correct value for jobGUID on the first pass through, but on the return to Success after the AJAX call, jobGUID changes to the word "success", with the double quotes.
How can I pass through that jobGUID to the Success function so I can use it to do more work depending on the AJAX response?
Thanks in advance....

Callback Issue in JavaScript

I am trying to execute a WCF service call, from function one(). Only once this is complete I want function two() to be executed. The issue I have is that function two() is invoked before function one() completes execution and the WCF service returns the result. How can I solve this please? I am using callback function, so I can't figure out why, given that the response does not exceed 3 seconds.
<script type="text/javascript">
var jsonGetFileResult = "";
function one(callback) {
setTimeout(function() {
//var jsonGetFileResult = "";
console.log('01: into one');
$.ajax({
type: 'GET',
url: ‘http: //wcf.google.com’, //this is the wcf call
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: {},
timeout: 10000,
success: function(data) {
jsonGetFileResult = stringifyNewsletter(data);
console.log('03: ' + jsonGetFileResult);
},
error: function(data) {
alert(error);
}
});
callback();
}, 3000);
}
function stringifyNewsletter(data) {
var removeHeader = JSON.stringify(data);
var file = removeHeader.split('"');
console.log('02: ' + file[3]);
return file[3];
}
function two(linkToNewsletter) {
window.open(linkToNewsletter, '_blank', 'location=yes');
return false;
}
/* now we make use of the callback */
one(function() {
alert(jsonGetFileResult);
// "one" triggers "two" as soon as it is done, note how "two" is a parameter
two(jsonGetFileResult);
});
</script>
You're invoking the callback outside of the ajax "success" function. The $.ajax() call is asynchronous — the call will return to your code essentially immediately, after launching the HTTP request and without waiting for it to finish.
If you move the line
callback();
to inside the "success" handler, then that will run after the HTTP request completes.
You need to put callback inside success function like that:
function one(callback) {
setTimeout(function() {
//var jsonGetFileResult = "";
console.log('01: into one');
$.ajax({
type: 'GET',
url: ‘http: //wcf.google.com’, //this is the wcf call
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: {},
timeout: 10000,
success: function(data) {
jsonGetFileResult = stringifyNewsletter(data);
console.log('03: ' + jsonGetFileResult);
callback();
},
error: function(data) {
alert(error);
}
});
}, 3000);
}

Two Ajax onclick events

So I have had to modify some old existing code and add another ajax event to onclick
so that it has onclick="function1(); function2();"
This was working fine on our testing environment as it is a slow VM but on our live environment it causes some issues as function1() has to finished updating some records before function2() gets called.
Is there a good way to solve this without modifying the js for function2() as this the existing code which is called by other events.
Thanks
Call function2 upon returning from function1:
function function1() {
$.ajax({
type: "POST",
url: "urlGoesHere",
data: " ",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
//call function2
},
error:
});
}
Or wrap them in a function that calls both 1 and 2.
You need to use always callback of ajax method, check out always callback of $.ajax() method http://api.jquery.com/jquery.ajax/.
The callback given to opiton is executed when the ajax request finishes. Here is a suggestion :
function function1() {
var jqxhr = $.ajax({
type: "POST",
url: "/some/page",
data: " ",
dataType: "dataType",
}).always(function (jqXHR, textStatus) {
if (textStatus == 'success') {
function2();
} else {
errorCallback(jqXHR);
}
});
}
I'm assuming you use Prototype JS and AJAX because of your tags. You should use a callback function:
function function1(callback) {
new Ajax.Request('http://www.google.nl', {
onSuccess: function(response) {
callback();
}
});
}
function function2(callback) {
new Ajax.Request('http://www.google.nl', {
onSuccess: function(response) {
callback();
}
});
}
function both() {
function1(function() {
function2();
});
}
Then use onclick="both();" on your html element.
Example: http://jsfiddle.net/EzU4p/
Ajax has async property which can be set false. This way, you can wait for that function to complete it's call and set some value. It actually defeats the purpose of AJAX but it may save your day.
I recently had similar issues and somehow calling function2 after completing function1 worked perfectly. My initial efforts to call function2 on function1 success didn't work.
$.ajax({
type: "POST",
url: "default.aspx/function1",
data: "",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: false, // to make function Sync
success: function (msg) {
var $data = msg.d;
if ($data == 1)
{
isSuccess = 'yes'
}
},
error: function () {
alert('Error in function1');
}
});
// END OF AJAX
if (isSuccess == 'yes') {
// Call function 2
}

Variable is undefined error (even if console.log shows variable)

My function looks like that
var mail_ntfy=$("#nav_mail"), question_ntfy=$("#nav_question"), users_ntfy=$("#nav_users");
function CheckAll(){
var data=checkFor("m,q,u");
if(mail_ntfy.attr("data-number")!=data.m_count && data.m_count!=0)
mail_ntfy.attr("data-number", data.m_count);
if(question_ntfy.attr("data-number")!=data.q_count && data.q_count!=0)
question_ntfy.attr("data-number", data.q_count);
if(users_ntfy.attr("data-number")!=data.u_count && data.u_count!=0)
users_ntfy.attr("data-number", data.u-count);
showNotes(data.msg);
chngTitle(data.msg);
}
$(document).ready(function () {
setInterval(CheckAll(), 10000);
})
function checkFor(param){
$.ajax({
url: "core/notifications.php",
type: "POST",
dataType: "json",
data: {
chk:param
},
success: function (data) {
if(data.status!="error") {
console.log(data);
return data;
}
}
});
}
I got 2 questions:
1) I see that, checkFor function returns result (console.log shows result) but still getting data is undefined error message on line if(mail_ntfy.attr("data-number")!=data.m_count && data.m_count!=0). What am I missing?
2) I want to execute, CheckAll in every 10 seconds. But it doesn't start more than 1 time. why setinterval doesn't work properly?
checkFor() does not return any result. The console.log() statement is in the anonymous function attached to the success handler of your AJAX request; its return does not return from the checkFor() function.
If you want checkFor to return the data the AJAX call has to be synchronous. This is, however, bad Javascript practice (for example, it will hang the execution of scripts on the page until the request is complete). Unfortunately this whole design is flawed, but you could use this code if you REALLY have to:
function checkFor(param){
var result;
$.ajax({
url: "core/notifications.php",
type: "POST",
async: false,
dataType: "json",
data: {
chk:param
},
success: function (data) {
if(data.status!="error") {
console.log(data);
result = data;
}
}
});
return result;
}
You can't return data from success callback. Instead you can call CheckAll from success callback like this
success: function (data) {
if(data.status!="error") {
console.log(data);
//return data;
CheckAll(data);
}
}
To run checkFor instead every 10 seconds you can set the timer from within success callback too. That will call the checkFor 10 seconds after every successful ajax request. Using setInterval can end up with multiple simultaneous ajax calls.
success: function (data) {
if(data.status!="error") {
console.log(data);
//return data;
CheckAll(data);
setTimeout(checkFor,10000);
}
}
And your updated checkAll would be like
function CheckAll(data){
if(mail_ntfy.attr("data-number")!=data.m_count && data.m_count!=0)
mail_ntfy.attr("data-number", data.m_count);
if(question_ntfy.attr("data-number")!=data.q_count && data.q_count!=0)
question_ntfy.attr("data-number", data.q_count);
if(users_ntfy.attr("data-number")!=data.u_count && data.u_count!=0)
users_ntfy.attr("data-number", data.u-count);
showNotes(data.msg);
chngTitle(data.msg);
}
You are calling Ajax asynchronously therefore the system wont wait for ajax to end in order to continue proccessing. You'll have to add
async:false,
To your ajax call, like this:
function checkFor(param){
$.ajax({
url: "core/notifications.php",
type: "POST",
async:false,
dataType: "json",
data: {
chk:param
},
success: function (data) {
if(data.status!="error") {
console.log(data);
var ret=data;
}
}
});
return ret;
}
Hope it helps!

Looping through DOM elements

So this is my function, it deletes people from a list if you click on certain part of the form:
function ParticipantsDeleteClick(model, url) {
for (i in model.Participants) {
$("#delete" + i).click(function () {
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ id: model.Participants[i].Id }),
success: function (result) {
result ? $("#participant" + i).remove() : alert("Delete failed");
},
error: function () {
alert("Could not get a response from the server.");
}
});
});
}
}
For some reason, it doesn't matter which person you click on, it will always delete the last person from the list. And it only works once because once the last "i" gets deleted, every other click function points to that dom element with the last i's value.
I don't know why every time I'm adding a click function it all points to the last i's value in the loop. I modified the function adding a temp variable that took i's integer value and that didn't work either:
function ParticipantsDeleteClick(model, url) {
for (i in model.Participants) {
var temp = parseInt(i);
$("#delete" + temp).click(function () {
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ id: model.Participants[temp].Id }),
success: function (result) {
result ? $("#participant" + temp).remove() : alert("Delete failed");
},
error: function () {
alert("Could not get a response from the server.");
}
});
});
}
}
So I'm not sure how I can get this to work.
i is always overwritten in the loop. You need a closure, eg by using $.each(function(){..}, or by wrapping the loop's body in a self-invoking function.
function ParticipantsDeleteClick(model, url) {
$.each(model.Participants, function(i){ //The `function` creates a closure
$("#delete" + i).click(function () {
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ id: model.Participants[i].Id }),
success: function (result) {
result ? $("#participant" + i).remove() : alert("Delete failed");
},
error: function () {
alert("Could not get a response from the server.");
}
});
});
}
}
Basically, you need to introduce a closure to capture the value of i each time around the loop. Using $.each() will introduce a closure for you (something like this)
function ParticipantsDeleteClick(model, url) {
$.each(model.Participants, function(i,v) {
$("#delete" + i).click(function () {
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ id: model.Participants[i].Id }),
success: function (result) {
result ? $("#participant" + i).remove() : alert("Delete failed");
},
error: function () {
alert("Could not get a response from the server.");
}
});
});
});
}
You have 3 scope levels here:
loop scope
click handler scope
ajax success handler scope
So you will need for each of those scope preserve and pass the variables. The .bind() method allows you to pass arguments to the callback from the outer scope and the context parameter allows you to pass parameters to the AJAX success callback. So:
$.each(model.Participants, function(index, participant) {
var data = { index: index, participant: participant };
$('#delete' + index).bind('click', data, function(evt) {
// at this stage evt.data will point to what the data variable was pointing
// from the outer scope but at the moment this handler was bound
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ id: evt.data.participant }),
context: evt.data.index,
success: function (result) {
// since we have used the context parameter at this stage
// this will point to this parameter which is simply the index
result ? $('#participant' + this).remove() : alert('Delete failed');
},
error: function () {
alert('Could not get a response from the server.');
}
});
});
});
Or to break this into separate functions to make it more clear:
function handleClick(evt) {
$.ajax({
url: url,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ id: evt.data.participant }),
context: evt.data.index,
success: ajaxSuccess,
error: ajaxError
});
}
function ajaxSuccess(result) {
result ? $('#participant' + this).remove() : alert('Delete failed');
}
function ajaxError() {
alert('Could not get a response from the server.');
}
and then finally:
function ParticipantsDeleteClick(model, url) {
$.each(model.Participants, function(index, participant) {
var data = { index: index, participant: participant };
$('#delete' + index).bind('click', data, handleClick);
});
}

Categories