How do I wait for multiple jquery posts to complete? - javascript

I'm trying to clear a busy icon and re-enable my delete button once the multiple jquery posts have completed. Here is my current code:
$('#deleteimgs').live('click', function(e) {
e.preventDefault();
if ($('input[name="chk[]"]:checked').length > 0 ) {
$('#deleteimgs').button('loading');
$('#saveicon').show();
var boxes = $('input[name="chk[]"]:checked');
$(boxes).each(function(){
var id = $(this).attr('id').substr(7);
var self = this;
$.post("/functions/photo_functions.php", { f: 'del', imgid: id}, function(data){
if (data.success) {
$(self).hide();
$("#img_"+id).hide(250);
}
}, "json");
});
$('#saveicon').hide();
$('#deleteimgs').button('reset');
}
});
My hide call and reset call are being trigger prior to completion of the foreach loop. Is there a way to wait for completion before making these two calls?
$('#saveicon').hide();
$('#deleteimgs').button('reset');

You should use the success callback method to complete any tasks once the HTTP request has finished. Inside of the callback you should keep track of how many requests have completed, and when your last request has finished, then execute the code of your desire.
You could restructure this code in a few ways, but, it should give you a general idea of how to handle the situation.
var boxes = $('input[name="chk[]"]:checked');
var totalBoxes = boxes.length;
var completedRequests = 0;
$(boxes).each(function(){
var id = $(this).attr('id').substr(7);
var self = this;
$.post("/functions/photo_functions.php", { f: 'del', imgid: id}, function(data){
if (data.success) {
$(self).hide();
$("#img_"+id).hide(250);
//Increment the complete request count.
completedRequests++;
//Check if the last request has finished. If it has, do your stuff!
if (completedRequests == totalBoxes) {
$('#saveicon').hide();
$('#deleteimgs').button('reset');
}
}
}, "json");
});

Try something like :
$(document).on('click', '#deleteimgs', function(e) {
e.preventDefault();
if ($('input[name="chk[]"]:checked').length > 0 ) {
$('#deleteimgs').button('loading');
$('#saveicon').show();
var boxes = $('input[name="chk[]"]:checked'),
xhr = [];
boxes.each(function(){
var self = this,
id = self.id.substr(7);
var request = $.post("/functions/photo_functions.php", { f: 'del', imgid: id}, function(data){
if (data.success) {
$(self).hide();
$("#img_"+id).hide(250);
}
}, "json");
xhr.push(request);
});
$.when.apply(null, xhr).done(function() {
$('#saveicon').hide();
$('#deleteimgs').button('reset');
});
}
});​
This will store all the requests in an array that is later passed to $.when, and when they are all done the done() function will be executed.

You need to count the number of posts you make, call an intermediary function to count the replys, then do the hide and reset after all calls have completed.
for example:
var postCount = 0;
function allPostsDone()
{
$('#saveicon').hide();
$('#deleteimgs').button('reset');
}
postCount += 1;
$.post("/functions/photo_functions.php",
{ f: 'del', imgid: id},
function(data)
{
if (data.success)
{
$(self).hide();
$("#img_"+id).hide(250);
}
postCount -= 1;
if (postCount == 0)
{
allPostsDone();
}
}, "json");

To follow up on DwB's answer, using async would be an easy way to supply the intermediary function. instead of:
$(boxes).each(function(){
Use:
async.parallel(boxes.toArray().map(function(elem){
var self = elem;
return function (callback) {
var id = $(self).attr('id').substr(7);
$.post("/functions/photo_functions.php", { f: 'del', imgid: id}, function(data){
if (data.success) {
$(self).hide();
$("#img_"+id).hide(250);
callback();
} else {
callback(new Error("request failed"));
}
}, "json");
}
}), function (err) {
if(err) {
console.log(err);
} else {
$('#saveicon').hide();
$('#deleteimgs').button('reset');
}
});
That should work.

Related

Javascript program not executing correctly

I'm new to javascript, but I can't get my head around this problem. I have a function that upvotes a game:
function upVoteGame(name) {
$.get("/get_gameValues", function(data) {
var alreadyExist = false;
var noVotes = false;
var games;
games = data;
for (var i = 0; i < games.length; i++) {
if (name === games[i].gameName) {
alreadyExist = true;
voteOperations();
if (userLoggedIn == false) {
alert("second");
swal("Cannot post votes", "Please log in or register to vote", "error");
}
if (noVotesLeft == false && userLoggedIn == true) {
$.ajax({
url: '/editVotes/' + games[i]._id,
type: 'PUT',
data: {
likes: games[i].likes + 1,
totalVotes: data[i].totalVotes + 1
},
success: function(result) {
alert(games[i].likes + 1);
}
});
}
refreshGameValues();
break;
}
}
//This is for us Developers!
if (!alreadyExist) {
$.post("/add_game_to_dB", {
gameName: name
}, function(result) {
alert("Introduced " + name);
});
}
});
}
Now I have the function that updates the user's votes left, voteOperations():
function voteOperations() {
$.get("/users/get_current_user", function(data) {
//var votes = 5;
for (var i = 0; i < data.length; i++) {
votesRemaining = data[i].votesRemaining;
userLoggedIn = true;
alert("votes left : " + votesRemaining);
if ((votesRemaining - 1) < 0) {
swal("No votes remaining", "Please wait 24 hours to get more votes", "error");
noVotesLeft = true;
}
if (noVotesLeft == false) {
$.ajax({
url: '/users/updateUserDetails/' + data[i].user_name,
type: 'PUT',
data: {
votesRemaining: votesRemaining - 1
},
success: function(result) {}
});
}
}
});
}
My problem is a simple problem. In the upVoteGame(name) function, I want the voteOperations() to execute before the if loop below it. However, when I run the code, the if loop below executes first and alerts the user that they are not logged in. When a user logs in, userLoggedIn is set to true, but the if loop executes firsts and tells them that they are not logged in, and then executes the voteOperations() function. I don't know why this is happening. How can I fix this so that voteOperations executes before the if loop?
This is because the voteoperations function has a get request which is asynchronous. You will need a callback function where you should include if condition
You can try:
function upVoteGame(name) {
vote(afterGet);
}
afterGet() {
if condition here
}
function vote(callback) {
$.get .... {
//after getting data
callback();
}
}
You problem occurs due to the asynchronous call of your $.get in the voteOperations function.
Since it is an asynchronous call your code continuous while your $.get is waiting to retrieve data and thus your if statement seems to trigger before your voteOperations function.
In simple words your function actually is triggered before the if statement but before it completes it's result the code continues and triggers your if statement.
You could put your if statement (logic) in the success callback of your vote operation function or use $.ajax with async:false which is not considered a good practice generally but I use it sometimes.
Something like that for example (for the second case)
$.ajax({
async: false,
.....
success: function (response) {
//
}
});
Asynchronous calls can be handled with jquery function Deffered
function upVoteGame(name) {
vote().then(doUpVoteGame(), handleError());
}
function doUpVoteGame() {
...
}
function handleError(e) {
console.error("fail", e);
}
function vote() {
var d = new $.Deferred();
$.get .... {
d.resolve();
}).fail(function(e) {
d.reject(e);
});
return d;
}

Wait for AJAX response before moving on with script

I have a script which runs 2 AJAX calls, the first checks that a record exists within a database. If it does this should not move on and the script should stop. The second submits a job.
My problem is that the job is being submitted before the first AJAX call has returned. My code looks something like this:
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
success: function( data ){
if (data.Response == "Success") {
var noresults = data.Results;
if (noresults > 0){
alert('this record id already exists!');
return false;
}
} else {
alert('an error occured');
return false;
}
}
});
} else {
alert('enter a record id');
return false;
}
// second ajax call goes here, which gets called regardless of the output of the ajax call above
Instead of putting the call to the second ajax method at the bottom of your code (where the comments currently are), put it in the "success" function of your first call. This method will only execute once the first call has finished. This is the only way to ensure that the second call does not happen too early. Ajax calls run asynchronously, so the normal flow of the browser is not interrupted. This is deliberate so that long-running calls don't lock up the browser for the user.
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
success: function(data) {
//check here if you want to call submitJob or not
//and call submitJob()
}
});
} else {
alert('enter a record id');
return false;
}
//call this ajax once you varified your condition from success callback of first one
function submitJob() {
//second ajax call goes here
}
You have to use jquery promise function for that which will wait for the first ajax request to complete then make another ajax request.
JQUERY PROMISE
OR
Put the second ajax request in the success function of first one, and make it happen when you want it to fire
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
success: function(data) {
//check here if you want to call submitJob or not
if (noresults > 0){ return false }
else { Job(); };
}
});
} else {
alert('enter a record id');
return false;
}
function Job() {
//another ajax call.
}
Hope it helps :)
try this: make async propety false
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
async : false, //added this
success: function( data ){
if (data.Response == "Success") {
var noresults = data.Results;
if (noresults > 0){
alert('this record id already exists!');
return false;
}
} else {
alert('an error occured');
return false;
}
}
});
} else {
alert('enter a record id');
return false;
}
OR
perform second ajax call in success function of first ajax call i.e. see comment
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
success: function( data ){
if (data.Response == "Success") {
var noresults = data.Results;
if (noresults > 0){
alert('this record id already exists!');
return false;
}
//perform 2nd ajax call here
} else {
alert('an error occured');
return false;
}
}
});
} else {
alert('enter a record id');
return false;
}

javascript callback function call itself until true

I am running a function that i need to keep running until i get a response example
exports.getJson = function(url, callback) {
var loader = Titanium.Network.createHTTPClient();
loader.open("GET", url);
loader.onload = function() {
var response = JSON.parse(this.responseText);
callback(response);
};
loader.onerror = function(e) {
callback(false);
};
// Send the HTTP request
loader.send();
}
ok the problem i am having is it will sometimes give me a response of null and i need it to run again.
so i am calling it like this.
url = 'http://example.com/test.json';
main.getJson(url, function(response) {
if(response){
addData(response);
}else{
//return no response i need to run the function again now until it comes back as true
}
});
Can anyone give me a good way to do this maybe try at least 3 times then return false???
Thanks
Just put the code in function and call it again:
var counter = 0;
function getData() {
main.getJson('http://example.com/test.json', function(response) {
if(response){
addData(response);
}
else if (counter < 3) {
counter++;
getData();
}
});
});

What design pattern should I apply when checking multiple ajax request completion?

I have 3 ajax call in one function and checkAjaxCompletion which checks each ajax completion flag.
What the code below does is send multiple separate ajax calls and interval method checks completion flags to determine whether to proceed or keep interval. (I know clearInterval is not shown but the point is I want to use something other than interval)
Current code is:
function manyAjax() {
setInterval( function() { checkAjaxCompletion(); } , 200);
ajax1();
ajax2();
ajax3();
}
function ajax1() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax2() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax3() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function checkAjaxCompletion() {
if(ajax1_flag == 1 && ajax2_flag == 1 && ajax3_flag == 1) {
//everything went success, do some process
}
else if(ajax1_flag == 2 || ajax2_flag == 2 || ajax3_flag == 2) {
//some ajax failed, do some process
}
else {
//all ajax have not been completed so keep interval i.e. do nothing here
}
}
But I'm hesitating to depend on using interval function because calling it so often seem such waste of memory. There must be better way to do. I'm thinking if observer pattern can be applied here but would like to hear opinions.
It is observer-notifier, if you want to call it that - but each of your ajax calls will more than likely have a callback in javascript when they complete. Why not call checkAjaxCompletion() at the end of each of them, and do nothing if you're still waiting on others?
Dustin Diaz does a great job with this example.
function Observer() {
this.fns = [];
}
Observer.prototype = {
subscribe : function(fn) {
this.fns.push(fn);
},
unsubscribe : function(fn) {
this.fns = this.fns.filter(
function(el) {
if ( el !== fn ) {
return el;
}
}
);
},
fire : function(o, thisObj) {
var scope = thisObj || window;
this.fns.forEach(
function(el) {
el.call(scope, o);
}
);
}
};
The publisher:
var o = new Observer;
o.fire('here is my data');
The subscriber:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
To unsubscribe:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
// ajax callback
this.ajaxCallback = function(){
$.ajax({
type: "POST",
url: ajax.url,
data: {key: value},
async : !isAll,// false使用同步方式执行AJAX,true使用异步方式执行ajax
dataType: "json",
success: function(data){
if(data.status == 'successful'){
selfVal.parent().find('.msg').addClass('ok').html(msg.ok);
}else if(data.status == 'failed'){
checkRet = false;
selfVal.parent().find('.msg').removeClass('ok').html(msg.error);
}else{
checkRet = false;
}
return this;
}
});
}
return this;
Maybe you want to check your inputvalue callback ajax in your form;
You can view my website Demo, hope help you.
http://6yang.net/myjavascriptlib/regForm
Okay my idea was to make your own object that can handle sending an array of requests, keep a history of each request and do what i'm gonna call 'postProccessing' on each response, here is a probably very dodgy bit of code to hopefully demonstrate what I am thinking.
var Ajax = function() {
var request, callback, lst;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
request.onreadystatechange = handleResponse;
this.history = [{}];
this.send = function(args) {
for (var i = 0; i < args.length; i++) {
if (args.url) {
request.open(args.type || 'GET', args.url);
}
request.send(args.data || null);
callback = args.callback;
lst++;
}
}
function handleResponse() {
var response = {
url: '',
success: true,
data: 'blah'
};
history.push(response);
if (postProccess()) {
callback();
}
}
function postProcess() {
if (this.history[lst].success) {
return true;
} else {
return false;
}
}
}

using SetTimeout with Ajax calls

I am trying to use setTimeout to check if data exists in a table:
If the data exists don't fetch data. If the data des not exist fetch the data using load and then do the same thing every x minutes.
Here is what I have so far. For some reason, the setTimeout does not work when it hits the If block.
I am not even sure if this is the best way to do this.
var sTimeOut = setTimeout(function () {
$.ajax({
url: 'CheckIfDataExists/' +
new Date().getTime(),
success: function (response) {
if (response == 'True') {
$('.DataDiv')
.load('GetFreshData/' + new Date()
.getTime(), { "Id": $("#RowID").val() });
}
},
complete: function () {
clearTimeout(sTimeOut);
}
});
}, 10000);
Any help will be greatly appreciated.
Updated ...
setTimeout(function(){checkData()}, 5000);
function checkData(){
$.ajax({
url: 'CheckIfDataExists/' +
new Date().getTime(),
success: function (response) {
if (response == 'True') {
$('.DataDiv')
.load('GetFreshData/' + new Date()
.getTime(), { "Id": $("#RowID").val() });
} else {
$('.OutOfWindow').html('No Data Found');
setTimeout(function () { checkData() }, 5000);
}
},
complete: function () {
// clearTimeout(sTimeOut);
}
});
}
Something like this should work, the first snippet is localized so I could test run it. I've explained the code and below it is what your code should be
Like you realized (from your update on your post) setTimeout only calls your target function once, so to keep checking you need to call it again if you do a check that fails.
See it on JsFiddle : http://jsfiddle.net/jQxbK/
//we store out timerIdhere
var timeOutId = 0;
//we define our function and STORE it in a var
var ajaxFn = function () {
$.ajax({
url: '/echo/html/',
success: function (response) {
if (response == 'True') {//YAYA
clearTimeout(timeOutId);//stop the timeout
} else {//Fail check?
timeOutId = setTimeout(ajaxFn, 10000);//set the timeout again
console.log("call");//check if this is running
//you should see this on jsfiddle
// since the response there is just an empty string
}
}
});
}
ajaxFn();//we CALL the function we stored
//or you wanna wait 10 secs before your first call?
//use THIS line instead
timeOutId = setTimeout(ajaxFn, 10000);
Your code should look like this :
var timeOutId = 0;
var ajaxFn = function () {
$.ajax({
url: 'CheckIfDataExists/' + new Date().getTime(),
success: function (response) {
if (response == 'True') {
$('.DataDiv').
load('GetFreshData/' + new Date().
getTime(), { "Id": $("#RowID").val() });
clearTimeout(timeOutId);
} else {
timeOutId = setTimeout(ajaxFn, 10000);
console.log("call");
}
}
});
}
ajaxFn();
//OR use BELOW line to wait 10 secs before first call
timeOutId = setTimeout(ajaxFn, 10000);

Categories