How to tell when multiple functions have completed with jQuery deferred - javascript

I have 3 functions which handle data pulled in from AJAX, they update the page after the ajax function is called.
When the AJAX function is called I show a loader, I want to hide the loader after the AJAX has completed and the functions have completed.
How can I use deferred with when and then in jQuery to test once all 3 function are completed.
Here is my AJAX code, this hides the loader on AJAX success at the moment, ideally this would be after the 3 functions have been completed / were successful.
The 3 functions receive data to process and display on the page, they are not AJAX functions.
function setUpStocking() {
$.ajax({
url: url,
cache: false,
beforeSend: function(){
// Show loader
$('.loader').show();
},
success: function(data){
updateMyList(data.gifts);
updateRecievedGift(data.recieved);
updateGiftsOpenedToday(data.opened);
// Hide loader
$('.loader').hide();
}
});
}
The functions are outside the AJAX function:
function updateMyList(gifts) {
// Get data, process it and add it to page
}
function updateRecievedGift(recieved) {
// Get data, process it and add it to page
}
function updateGiftsOpenedToday(opened) {
// Get data, process it and add it to page
}

You need to first make each of these functions return the deferred object jQuery gives you when you make an AJAX request. Then you can put those in to an array, and apply that to $.when(). Something like this:
var deferreds = [];
$.ajax({
url: url,
cache: false,
beforeSend: function(){
// Show loader
$('.loader').show();
},
success: function(data){
deferreds.push(updateMyList(data.gifts));
deferreds.push(updateRecievedGift(data.recieved));
deferreds.push(updateGiftsOpenedToday(data.opened));
$.when.apply(deferreds).done(function() {
// Hide loader
$('.loader').hide();
});
}
});

There should be $, inside .apply to make above code work.
$.when.apply($, deferreds).done(function() {
// Hide loader$('.loader').hide();
});

Related

Saving Variable in AJAX success call to pass in Another AJAX success call

Creating a 'refresh' button via jQuery, AJAX and PHP.
This particular one I'm having control two DOM instances (divs) - #sold-container, and also #totalorderswidget.
$(document).ready(function() {
$(function() {
$('#orderfeed').on('click', function() {
var orders;
$.ajax({
type: 'POST',
url: 'liveorderwidget.php',
beforeSend: function() {
$('#sold-container').html('<div class="page-loader"></div>');
$.ajax({
url: "totalorderswidget.php",
beforeSend: function() {
$('#totalorderswidget').html('<div class="page-loader"></div>');
},
success: function(orderdata) {
// $('#totalorderswidget').html(orderdata);
orders = orderdata;
}
});
},
success: function(solddata) {
$('#sold-container').html(solddata);
$('#totalorderswidget').html(orders);
}
})
});
});
});
I didn't like how each DIV was updating and showing my page-loader CSS at different times, so I thought I'd try and grab the data to pass and display them both at the same time (get data from the first ajax call, display both on the second).
This is working as two normal AJAX calls, and each appends the success html to each id on it's own. (uncommenting // $('#totalorderswidget').html(orderdata); works),
but initializing a variable like var orders; outside the functions and trying to put the data in the success call (orders = orderdata;) does not work.
Doing a console.log on the first AJAX success call (orderdata) brings back the expected response, but trying to use it in the second AJAX call ($('#totalorderswidget').html(orders);) does not work and a console.log brings back undefined for the order variable.
What must I change in order to grab data from the first success call function and bring this data into the second/final ajax success call?

How to load function after ajax load all DOM elements

I have an issue with a function that should be loaded after all content is ready.
I have a massive ajax call 1700 line of code.
How my code works: php file getting data from 3 tables in my database and converting it to JSON. I opening the JSON file and creating 1 element for 1 database result.
For now, I have around 100 results but I will have around 1000 in the final step. So I create loading to put before the page will be loaded. But because the main content is created by js, sometimes my loading fade out 1-2 sec before content is loaded. I can use js or jquery. For now, I used something like that :
$(window).on ('load', function (){
setTimeout(function (){
$("#loading").fadeOut('slow');}, 1000)});
Execute the function once you received data through AJAX. Check the code snippet below
$.ajax({
url: '/URL/TO/CODE',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') //This is optional if you are using x-csrf-token validation of if u want to pass any header data
},
type: "post",
data: {
data:data //In case if you need to pass any data
},
dataType: 'json',
cache: false,
before:function(){
//Is you want to show any loader or anything while ajax is being executed.
},
success: function (response) {
//Once your ajax is success you can call your custom function to do things with the data
myCustomFunction();
},
error: function (res) {
console.log(res);
}
});
function myCustomFunction(){
//This to be executed when all data are filled by ajax and page is loaded
}
Hope this helps.
$(window).ready(function (){
setTimeout(function(){ $("#loading").fadeOut('slow'); }, 3000);
});

Alternative for Multiple ajax to get data rails

I have 4 tabs on my page:
MY Queue | Today | Followup | Upcoming
on page load i fire 4 ajax calls to get data from controller for all these tabs and once i get data i create list for each of the tabs.
But as ajax is asynchronous i get anomalies in my data, are there any better ways to achieve this.
i have 4 ajax calls similar to below call:
$.ajax({
url: '/opd_clinical_workflow/get_appointment_lists',
dataType: 'json',
data: {
current_date: current_date,
department_id: current_department,
doctor: current_doctor,
status: current_status,
source: "list",
q: $( "#search_appointment").val(),
},
success: function(res){
console.log(tab,res)
_this.updateMyQueueSummary(res,id,tab);
},
error: function(err){
console.log(err);
}
});
updateMyQueueSummary:
Puts data in respective tabs
createSummaryAppointment:
Creates html for me and is called in updatesummary
Chaining AJAX is your best option:
$.ajax({
url: "somewhere/1"
})
.always(function(reponse1) {
//Do something with the response
document.write("<p>1</p>");
//Then call next part
$.ajax({
url: "somewhere/2"
})
.always(function(reponse2) {
//Do something with the response
document.write("<p>2</p>");
//Then call next part
$.ajax({
url: "somewhere/3"
})
.always(function(reponse3) {
//Do something with the response
document.write("<p>3</p>");
//Then call next part
$.ajax({
url: "somewhere/4"
})
.always(function(reponse4) {
//Do something with the response
document.write("<p>4</p>");
//Now finalize it
document.write("<p>Final</p>");
})
})
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Notice i am using always instead of done because i don't have anywhere to actually get data from.
All the jQuery ajax methods return promise objects. This are kind of like an IOU note from a friend. You don't have the data now but it will be there at some point.
They are an extremely powerful tool if you want to avoid what is called "callback soup" where you nest ajax callbacks until the code is both unreadable and brittle.
var promise = $.ajax('/foo');
promise.pipe(function(data){
return $.ajax('/bar?foo=' + data['foo']);
});
promise.done(function(data){
// ajax call to '/bar?foo=' is complete
});
You can use jQuery.when to combine two promises. This is really useful when you want to fire two asynchronous ajax calls at once but you need the results of both to continue.
var calls = $.when( $.ajax('/foo'), $.ajax('/bar') );
calls.done(function(response_a, response_b){
// both ajax calls are complete.
});

Dialog popup and spinner not behaving correctly

I want to popup/display a dialog. It has two tabs and in each of these tabs there is a table (lets say table1 and table2).
Both of these tables contain data those are populated by a rest/ajax service (lets say service1 and service2).
When each of these rest services completes, the table component is populated with the data.
On top of this, the dialog has a spinner widget activated when the dialog first pops up.
The spinner widget is deactivated when BOTH of the rest services have completed.
For table1 I have code that looks a bit like this :
this.updateTable1 = function (dialog)
{
dialog.setSpinner(true)
var call = {}
call.url = 'service1';
call.xmlHttpReq = $.ajax({
url: url,
dataType: 'json',
async: true,
type: 'GET'
}).always(
function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown)
{
dialog.table1.loadData(processedDataOrXHRWrapper);
dialog.setSpinner(false)
});
};
For table2 the code is pretty much the same.
Which means that it also has dialog.setLoading(false). This means that whichever process finishes first, the spinner is deactivated, which is incorrect behaviour.
Somehow the two ajax calls need to know about each other, but I don't like that idea :(. Should I have some kind of third object that stores state of which processes have finished?
I tried using ajax calls in sync mode, but that just blocks the display thread in the browser.
You can use Deferred promises to implement this.
var updateTable1 = function (dialog)
{
return $.ajax({
url: url,
dataType: 'json',
async: true,
type: 'GET'
}).always(
function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown)
{
dialog.table1.loadData(processedDataOrXHRWrapper);)
});
};
// and same for updateTable2
dialog.setSpinner(true);
$.when(updateTable1(dialog), updateTable2(dialog)).always(function() {
dialog.setSpinner(false);
});
Only issue with the above is that, if the ajax call in updateTable1 or updateTable2 fails, the always function is immediately called. If you don't want this - see the $.whenall function in the answer to this question:
jquery deferred - "always" called at the first reject

how to call a specific function on every ajax request

I have a problem, that I have several pages in my project and I used a lot of ajax requests in my project, but now I think that whenever an ajax request is called a function will called and whenever that request ends another function will call. How can I do this globally I know I can put this in every ajax request but I need a solution which I do in one place and it works all over the project.
$(document).read(function(){
// Suppose this document load function is written on layout page and every page is inherited from this page
});
Use ajaxSetup, for example
$.ajaxSetup({
beforeSend: function() {
console.log('test');
},
complete: function() {
console.log('completed');
}
});
will setup beforeSend handler for every ajax request. Note that ajaxSetup can take any option that $.ajax can.
You should create a wrapper function for your ajax, then use that function. that way, you have "central" control over the ajax call. something like:
//fast and crude way to extend jQuery
$.fn.customAjax = function(params){
//contains defaults and predefined functions
var defaults = {
complete : function(){...default complete hander...},
beforeSend : function (){...default beforeSend handler}
...
}
//merge settings
var finalParams = $.extend({},defaults,params);
//call ajax and return the deferred
return $.ajax(finalParams);
}
//use it like
$.customAjax({
url : ...,
method : ...,
data: ...,
complete : function(){...} //redefining in the call will override the defaults
});
.ajaxStart
Register a handler to be called when the first Ajax request begins.
.ajaxSucess
Attach a function to be executed whenever an Ajax request completes successfully.
for Detail doc:
http://api.jquery.com/category/ajax/
Try something like this:
$.ajax({
url: "test.html",
context: document.body
}).done(function() {
$.ajax({
url: "anotherMethod.html",
context: document.body
});
});
});
That means whenever ajax call completed successfully call your desire call.
It doesn't have a bug when complete. Click on Like, if work for you
$(document).ajaxSend(function(event, jqXHR, settings) {
$('#general-ajax-load ').fadeIn();
});
$(document).ajaxComplete(function(event, jqXHR, settings) {
$('#general-ajax-load ').fadeOut();
});

Categories

Resources