Elegant javascript - making function fire when 3 different AJAX requests have happened - javascript

I have three different AJAX queries that I want to hit various services. When they've all come back (or timed out) I'd like them to call a function.
I can imagine lots of ways of doing this, like having an intermediate function count when all the requests have come in, but is there a beautiful solution?

jQuery allows you to do what you want. See
http://www.erichynds.com/jquery/using-deferreds-in-jquery/
Naturally this only works if you are using jQuery, or can use jQuery.

If you are using jQuery 1.5 or later, you can use the jQuery.when method. For example:
$.when($.ajax("/page1.php"),
$.ajax("/page2.php")).done(function(a1, a2) {
/* a1 and a2 are arguments resolved for the
page1 and page2 ajax requests, respectively */
var jqXHR = a1[2]; /* arguments are [ "success", statusText, jqXHR ] */
if ( /Whip It/.test(jqXHR.responseText) ) {
alert("First page has 'Whip It' somewhere.");
}
});
Otherwise, see the Promises/A design pattern.

You can accomplish this easily with jQuery using the complete callback
var checked = 0;
$(function() {
$.ajax({ url: "1st ajax", complete: function(){ checked++; Check(); }});
$.ajax({ url: "2nd ajax", complete: function(){ checked++; Check(); }});
$.ajax({ url: "3rd ajax", complete: function(){ checked++; Check(); }});
}
function Check() {
if (checked >= 3) {
// all 3 have been successfully completed or timedout
}
}
or using then() deferred object to call the sequentially:
$.get("1st ajax").then(function(){
$.get("2nd ajax").then(function(){
$.get("3rd ajax").then(function(){
// call something
});
});
});
or using then() deferred object to call them without waiting with Check() method:
$.get("1st ajax").then(function(){ checked++; Check(); });
$.get("2nd ajax").then(function(){ checked++; Check(); });
$.get("3rd ajax").then(function(){ checked++; Check(); });

Hmm, maybe you could have a boolean value set to true once the last function called is executed fully? I suppose that this would pose a problem if the functions are being executed asynchronously, though.

Related

Alert before Ajax request in a loop with JQuery

I am trying to have a loop that asks the user for a confirmation before doing a synchronous ajax request and it is not working in order. This is my code:
<script>
$(document ).ready(function() {
for(var i = 0; i < 3; i++) {
alert("iteration "+i);
$(".demo").easyOverlay("start");
$.ajax({
async: false,
url: "http://rest-service.guides.spring.io/greeting"
}).then(function(data) {
$('.demo').append(data.id);
$('.demo').append(data.content);
$(".demo").easyOverlay("stop");
});
}
});
</script>
The behaviour I am having with my code is like this:
Ask for the first confirmation.
Ask for the second confirmation.
Ask for the third confirmation.
Executed the three ajax calls one after the other.
It looks like for some reason all the ajax calls gets delayed until the alerts are all confirmed and I don't know why. I tried to achieve my same goal without using a loop and by repeating the code 3 times and I get the same exact strange behaviour.
Edit:
If i put the following line in 'then()' to check if the html is actually modified I can see in the console that the things actually happens in order and they just don't appears in the browser until I confirm every alert and that's what gives the impression that the order of execution is not correct. So I need to figure out why reflecting the changes done to the html is delayed and is not done immediately.
console.log($('.demo').html());
IMO jQuery.Deferred() object will be the most promising way.
The Deferred object, is a chainable utility object created by calling the jQuery.Deferred() method. It can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.
deferred objects can be used for processing asynchronous events - you initiate an action and then register a callback which will be invoked when the action has completed. This includes AJAX, although there are plenty of other uses too.
Where asks for resolved
function callAjaxMethod(url, step) {
return $.Deferred(function() {
//Confirm box for use inputs
if(confirm(step))
{
//Ajax call
$.ajax(url).done(function(data){
//Do something
//Update your HTML if needed
});
}
setTimeout(function() {
//This will resolve your call again
this.resolve();
}.bind(this), 1000);
})
}
Deferred object
var defer = $.Deferred().resolve();
var counters = [1, 2, 3, 4, 5];
$.each(counters, function(key, value) {
defer = defer.then(function() {
return callAjaxMethod('URL', value);
});
});
It will call when all done
defer.then(function() {
//It will call when all done
});
Few of the documentation
Official jQuery.Deferred
Call ajax via jQuery deferred's
Article on Multiple jQuery promises
Hope this helps you :)
var $demo = $('#demo');
var ajaxURL = 'https://jsonplaceholder.typicode.com/posts';
function callAjaxMethod(url, step) {
return $.Deferred(function() {
//Confirm box for user inputs
if(confirm(step))
{
//Ajax call
$.ajax(url).done(function(data){
//Do something
//console.log(data);
//Update the HTML OK
$demo.append(step + ": Success" + "<br/>");
});
}
else
{
//Update the HTML when cancel
$demo.append("<font color='red'>"+ step +": Cancelled </font>" + "<br/>");
}
//Use timeout to get the resolved
setTimeout(function() {
this.resolve();
}.bind(this), 1000);
})
}
//Defer object
var defer = $.Deferred().resolve();
var counters = ['call 1', 'call 2', 'call 3', 'call 4', 'call 5'];
//Loop your calls
$.each(counters, function(key, value) {
defer = defer.then(function() {
return callAjaxMethod(ajaxURL, value);
});
});
defer.then(function() {
//It will call when all done
$(demo).append("<br/><br/>"+"ALL DONE");
});
div
{
color: blue;
font-size: 14px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="demo"></div>
That is because you should do the looping inside the Ajax request callback.
When you do it this way, the whole code is executed in a synchronic manner, whilst if you were to do so when the Ajax request callback is invoked, the requests and alerts would be executed like you would expect.
Edit:
Here is an example: (generic, you can customize it to your needs)
do(3)
function do(i) {
if (i === 0) return
$.ajax({...}).then(function() {
alert(...)
do(i-1)
})
}
Everytime ajax call fire it first ask for confirmation. If you allow then only ajax call fire and call for next ajax call and ask for confirmation and so on..
Please check below snippet for more understanding.
//call first time
doAjax(1,3)
//Function to call ajax repeatedly
function doAjax(arrCount,maxCount)
{
if (confirm("iteration "+arrCount)) {
$.ajax({
url: 'myUrl',
type: "POST",
data: {
// data stuff here
},
success: function (data) {
arrCount++;
//Next ajax call when current ajax call has been finished.
if(arrCount<=maxCount){
doAjax(arrCount,maxCount);
}
}
});
}
}

How to call this function automatically

Im using the following function to call an ajax request, and fill certain corresponding divs with the response:
$( function() {
$(document).ready(function() {
var postData = "";
$.ajax( {
url : \'functions/ajax_api.php?\',
type : \'post\',
data : postData,
success : function( resp ) {
$(\'#id1\').html($(\'#id1\' , resp).html());
$(\'#id2\').html($(\'#id2\' , resp).html());
}
});
return false;
});
});
The function works fine. My question is how can I call it automatically every few seconds?
I tried using window.setTimeout(function, 3000) but I couldnt set it up correctly.
use setInterval(); instead of .setTimeout()
Let me help you a little bit with that
var interval , setItinterval; // just a variables you can change names
interval = function(){
// ajax code here
}
to run it .. use:
setItinterval = setInterval(interval , 3000);
to stop it .. use
clearInterval(setItinterval);
Make sure to read setInterval for more information.
For Complete answer and Last thing I want to say when using setInterval(); Its better to use visibilitychange to avoid server error , server load or something like that
document.addEventListener('visibilitychange',function(){
if(document.visibilityState == 'visible'){
// user view the page
}else{
// user not see the page
}
});
You can use setTimeout() or setInterval, but setInterval may result in multiple simultaneous ajax calls if those calls take too long to respond. That isn't a problem if you call setTimeout() in the ajax success callback.
To use setTimeout(), first wrap your ajax call in a function. You can then add a call to setTimeout() to the ajax success callback. You also need to call the function once to start of the looping.
$(function() {
function postData() {
var postData = "";
$.ajax({
url: 'functions/ajax_api.php?',
type: 'post',
data: postData,
success: function(resp) {
$('#id1').html($('#id1', resp).html());
$('#id2').html($('#id2', resp).html());
// Call postData again after 5 seconds.
setTimeout(function() { postData(); }, 5000);
}
});
}
// Call postDate the first time to start it off.
postData();
});
Note: With the call to setTimeout in the success callback, the cycle will break if an ajax call fails. You may want that, but if you want it to act more like setInterval, you can place the call to setTimeout in the complete callback.
Here's some example code that will do it (note that it runs the function when the document loads, and then starts the interval). You can always use clearInterval(refresh_interval) if you need to stop it.
var refresh_interval;
function update_content() {
$.ajax({
url : \'functions/ajax_api.php?\',
type : \'post\',
data : postData,
success : function( resp ) {
$(\'#id1\').html($(\'#id1\' , resp).html());
$(\'#id2\').html($(\'#id2\' , resp).html());
}
});
}
$(document).ready(function() {
update_content();
setInterval(update_content, 3000);
}
The relevant documentation for using intervals is here: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval
Though you may want to look into Server Sent Events, it's probably a better solution for what you want.

$.when().then() not working with nested ajax calls

I have been trying to scroll the page to a dynamic div that is created by the an ajax call.
When #divnotifications div clicked (below), I make the first ajax call that adds the Post details, then within this ajax call, another ajax call is made to add the related comments to the div.
The part explained so far works great. Then, I use $.when().then() to scroll to a div item created based on the ajax calls. However, the page does not scroll to the element that was created by LoadCommentsForPost ajax call.
Did I get the logic of $.when().then() wrong?
$(document).on('click', '#divnotifications div', function (event) {
event.preventDefault();
$.ajax({
//other details
success: function (postid) {
$.when(DisplayPostWithFullDetails(postid)).then(function () {
//scroll to the content created by
//LoadCommentsForPost function nested
//inside DisplayPostWithFullDetails
});
}
});
});
function DisplayPostWithFullDetails(postId) {
$.ajax({
//other details
success: function (post) {
//The code to build the div to display the post -- working fine
LoadCommentsForPost(post.PostId);
}
});
}
function LoadCommentsForPost(postid) {
$.ajax({
//other details
success: function (response) {
var comments = JSON.parse(response);
DisplayComments(comments);//builds the div to display the comments - working fine
}
});
}
UPDATED CODE
After receiving some feedback, I ended up with the following code. However, it is still not working. It works only if I add some delay to make sure the div is loaded:
$(document).on('click', '#divnotifications div', function (event) {
event.preventDefault();
$.ajax({
//other ajax stuff
success: function (postid) {
DisplayPostWithFullDetails(postid).done(function () {
setTimeout(function () {
var scrollto = $("div[data-" + type.toLowerCase() + "displayform='" + relateditem + "']").offset().top;
$("html, body").animate({ scrollTop: scrollto }, 600);
}, 500);
});
}
});
});
function DisplayPostWithFullDetails(postId) {
jQuery.support.cors = true;
return $.ajax({
//other ajax stuff
success: function (post) {
post = JSON.parse(post);
//display the post details
LoadCommentsForPost(post.PostId);
}
});
}
function LoadCommentsForPost(postid) {
var promise = new $.Deferred();
jQuery.support.cors = true;
$.ajax({
//other ajax stuff
success: function (response) {
var comments = JSON.parse(response);
DisplayComments(comments);//this is not ajax
promise.resolve('loadedcomments');
}
});
return promise;
}
Did I get the logic of $.when().then() wrong?
Yes, you need to return a promise from the functions if you want to use the function with $.when:
function DisplayPostWithFullDetails(postId) {
return $.ajax({...
// ^^^^^^
That said, wrapping a single promise in $.when is useless.
$.when(DisplayPostWithFullDetails(postid)).then(function () {
should just be:
DisplayPostWithFullDetail(postid).then(function () {
Did I get the logic of $.when().then() wrong?
No, but you are NOT returning the promise so you can't use the promise functions like .then().
UPDATE:
I use $.when().then() to scroll to a div item created based on the ajax calls. However, the page does not scroll to the element that was created by LoadCommentsForPost ajax call.
For me this means that you need to wait that both ajax calls are resolved.
This fiddle show how it should work emulating the ajax call using setTimeout Fiddle.
Your code may look similar to:
function DisplayPostWithFullDetails(postId) {
var promise = new $.Deferred();
$.ajax({
//other details
success: function (post) {
//The code to build the div to display the post -- working fine
LoadCommentsForPost(post.PostId).then(function() {
promise.resolve();
});
}
});
return promise;
}
function LoadCommentsForPost(postid) {
return $.ajax({
//other details
success: function (response) {
var comments = JSON.parse(response);
DisplayComments(comments);//builds the div to display the comments - working fine
}
});
}
Now when you execute the function DisplayPostWithFullDetails it return a promise.
So you can use .then() method;
DisplayPostWithFullDetails(postid)).then(function () {});
or...
var promise = DisplayPostWithFullDetails(postid);
promise.then(function(data){});
Also the major advantage of use $.when() is that you can execute the .then() method when all the promises that you pass to it are resolved.
There are not need to use it when you are waiting for a single promise.

help with jquery ajax success event

I'm having an issue with my update button and jquery ajax. Right now when I click on my update button, it saves whatever updated data to the database. My goal is I want to slide up a message if the update is successful. I was looking at ajax post and using the success event seems like it would work but I dont know how to incorporte it. How would I do this? Would it be something like this?
$(document).ready(function(){
$('#divSuccess').hide();
$('#btnUpdate').click( function() {
alert('button click');
$.ajax({
url: "test.aspx",
context: document.body,
success: function(){
$('#divSuccess').show("slide", { direction: "down" }, 3000);
$('#divSuccess').hide("slide", { direction: "down"}, 5000);
}
});
});
});
check out this question for an example on how to handle the success event. Hope this helps!
$("#targetDiv").load("page.php",$("#form").serializeArray(),function (response)
{
if (response == '0' && response != '')
alert('Request not sent to server !\n');
else if(response == '-1')
alert('Please write some more !\n');
else
{
alert("success! ");
}
}
);
i've echo ed 0 and -1 for failure and other for success
In the jquery post function, you can execute some callback function.
function (data, textStatus) {
// data could be xmlDoc, jsonObj, html, text, etc...
this; // the options for this ajax request
// textStatus can be one of:
// "timeout"
// "error"
// "notmodified"
// "success"
// "parsererror"
// NOTE: Apparently, only "success" is returned when you make
// an Ajax call in this way. Other errors silently fail.
// See above note about using $.ajax.
}
http://docs.jquery.com/Post
With at least jQuery 1.5, you've got deferred objects and new syntax for AJAX events (including success).
var $ajaxcall = $.ajax({
url : 'myurl.svc/somemethod',
data : '{ somedata : "sometext" }'
});
$ajaxcall.success(function() {
// do something on successful AJAX completion
});
Of course you can chain that as well, and call something along the lines of $.ajax().success() or something.
Just wrote a blog post on it myself, if you're interested in reading more.

Abort all jQuery AJAX requests globally

Is there a way to abort all Ajax requests globally without a handle on the request object?
The reason I ask is that we have quite a complex application where we are running a number of different Ajax requests in the background by using setTimeOut(). If the user clicks a certain button we need to halt all ongoing requests.
You need to call abort() method:
var request = $.ajax({
type: 'POST',
url: 'someurl',
success: function(result){..........}
});
After that you can abort the request:
request.abort();
This way you need to create a variable for your ajax request and then you can use the abort method on that to abort the request any time.
Also have a look at:
Aborting Ajax
You cannot abort all active Ajax requests if you are not tracking the handles to them.
But if you are tracking it, then yes you can do it, by looping through your handlers and calling .abort() on each one.
You can use this script:
// $.xhrPool and $.ajaxSetup are the solution
$.xhrPool = [];
$.xhrPool.abortAll = function() {
$(this).each(function(idx, jqXHR) {
jqXHR.abort();
});
$.xhrPool = [];
};
$.ajaxSetup({
beforeSend: function(jqXHR) {
$.xhrPool.push(jqXHR);
},
complete: function(jqXHR) {
var index = $.xhrPool.indexOf(jqXHR);
if (index > -1) {
$.xhrPool.splice(index, 1);
}
}
});
Check the result at http://jsfiddle.net/s4pbn/3/.
This answer to a related question is what worked for me:
https://stackoverflow.com/a/10701856/5114
Note the first line where the #grr says: "Using ajaxSetup is not correct"
You can adapt his answer to add your own function to window if you want to call it yourself rather than use window.onbeforeunload as they do.
// Most of this is copied from #grr verbatim:
(function($) {
var xhrPool = [];
$(document).ajaxSend(function(e, jqXHR, options){
xhrPool.push(jqXHR);
});
$(document).ajaxComplete(function(e, jqXHR, options) {
xhrPool = $.grep(xhrPool, function(x){return x!=jqXHR});
});
// I changed the name of the abort function here:
window.abortAllMyAjaxRequests = function() {
$.each(xhrPool, function(idx, jqXHR) {
jqXHR.abort();
});
};
})(jQuery);
Then you can call window.abortAllMyAjaxRequests(); to abort them all. Make sure you add a .fail(jqXHRFailCallback) to your ajax requests. The callback will get 'abort' as textStatus so you know what happened:
function jqXHRFailCallback(jqXHR, textStatus){
// textStatus === 'abort'
}

Categories

Resources