On my website (MVC and web API) I have added a preloader for a better user experience purpose.
I have added the preloader at two points:
After Login, between the user is authenticated and the redirection to the homepage.
In every page that loads data from the server.
I did it with an image that I show when the page/data loads and I hide when the data is fully loaded.
<div id="dvReqSpinner" style="display: none;">
<br />
<center><img src="~/images/loading_spinner.gif" /></center>
<br />
</div>
And with jquery I show and hide it:
$("#dvReqSpinner").show();
$("#dvReqSpinner").hide();
It's a little bit anoying to keep showing and hiding an image every time I need to load data (using an AJAX call to web API, authenticating the user etc.. - Every action that takes time and I want to show the user that something is "happening"), isn't there any "automatic" option to have a preloader on a website?
I don't know if its the case, but if you use jquery ajax to handle your requests, you can do something like this:
$(document).ajaxStart(function() {
// every time a request starts
$("#dvReqSpinner").show();
}).ajaxStop(function() {
// every time a request ends
$("#dvReqSpinner").hide();
});
EDIT:
If you want to avoid showing the spinner for fast requests, i think this can make it work:
var delayms = 3000; // 3 seconds
var spinnerTimeOut = null;
$(document).ajaxStart(function() {
// for every request, wait for {delayms}, then show spinner
if(spinnerTimeOut!=null){
clearTimeout(spinnerTimeOut);
}
spinnerTimeOut = setTimeout(function(){
$("#dvReqSpinner").show();
}, delayms);
}).ajaxStop(function() {
// every time a request ends
clearTimeout(spinnerTimeOut); // cancel timeout execution
$("#dvReqSpinner").hide();
});
Give it a try. i couldn't test it -.-'
To show or hide a loading indicator in a single page app, I would add and remove a CSS class from the body:
#dvReqSpinner {
display: none;
}
body.loading #dvReqSpinner {
display: block;
}
and
$("body").addClass("loading");
$("body").removeClass("loading");
Primarily this would make the JS code independent on the actual page layout, so it's "nicer" but not really "less work".
To do it "automatically", I recommend abstracting your Ajax layer into a helper object:
var API = {
runningCalls: 0,
// basic function that is responsible for all Ajax calls and housekeeping
ajax: function (options) {
var self = this;
self.runningCalls++;
$("body").addClass("loading");
return $.ajax(options).always(function () {
self.runningCalls--;
if (self.runningCalls === 0) $("body").removeClass("loading");
}).fail(function (jqXhr, status, error) {
console.log(error);
});
},
// generic GET to be used by more specialized functions
get: function (url, params) {
return this.ajax({
method: 'GET',
url: url,
data: params
});
},
// generic POST to be used by more specialized functions
post: function (url, params) {
return this.ajax({
method: 'POST',
url: url,
data: params
});
},
// generic POST JSON to be used by more specialized functions
postJson: function (url, params) {
return this.ajax({
method: 'POST',
url: url,
data: JSON.stringify(params),
dataType: 'json'
});
},
// specialized function to return That Thing with a certain ID
getThatThing: function (id) {
return this.get("/api/thatThing", {id: id});
}
// and so on ...
};
so that later, in your application code, you can call it very simply like this:
API.getThatThing(5).done(function (result) {
// show result on your page
});
and be sure that the low-level stuff like showing the spinner has been taken care of.
You can use global ajax handlers for this.
This code will execute whenever you make an ajax request. all you have to do here is enable your spinner.
$( document ).ajaxSend(function() {
$("#dvReqSpinner").show();
});
This code will execute once your ajax request succeeded. all you have to do here is enable your spinner.
$( document ).ajaxSuccess(function( event, request, settings ) {
$("#dvReqSpinner").hide();
});
You can also use other global ajax function to handle things like showing a popup when a ajax request fails using ".ajaxError()"
Below link will have details of all the other functions
https://api.jquery.com/category/ajax/global-ajax-event-handlers/
Related
Hello i am working on a PHP Project where i need to load some request using ajax request. Below are my request function.
Function One: When showNotify event is click i call the ajax request to get content and use ajaxStart to show spinner untill the content is fully ready!
//* First click load nofication
$(document).on('click', '#showNotify', function() {
let check = $(this).data('check');
if(check === 0) {
//* Process notification
$(this).attr('data-check', 1);
//* Load ajax request
$(document).ajaxStart(function() {
$('#notify-wait').show();
});
$(document).ajaxComplete(function() {
$('#notify-wait').hide();
$('#list-noti').show();
});
$.ajax({
url: '/list-dd-notifications',
method: 'GET',
success: function() {
$('#notif-unread').hide();
}
});
}
});
Function Two: i need to check from the server side to see if user has a new unready notify and show up the new notification sign.
function checkNewFotify() {
$.ajax({
url: '/check-notifications',
method: 'GET',
success: function(data) {
if(data) {
if($('#notif-unread').is(":hidden"))
{
$('#notif-unread').show();
}
}
else
{
if($('#notif-unread').is(":visible"))
{
$('#notif-unread').hide();
}
}
}
});
}
//* check for new notification
setInterval(() => {
checkNewFotify();
}, 5000);
Problem: Any time the showNotify is dropdown at first it show the spinner the loader until the request is fully loaded also if the function checkNewFotify is doing is job by refreshing every 5 secs to check the server for new notification the ajaxStart in showNotify will be affected by showing the spinner loader every time the checkNewFotify is refreshing in background.
Please how can i stop it from showing the spinner loader whil it refreshing every 5 seconds.
Set the global option to false on the ajax on checkNewFotify() this will prevent handlers like ajaxStart from firing.
$.ajax({
url: '/check-notifications',
method: 'GET',
global: false,
});
Hello I'm working on a website with a color slider that append a specific color page to the DOM after a slide change. I want people to still be able to go through the different slide pretty quickly and load the ajax page only if the user didn't change the slide for a specific time (for example 1000ms).
I tried setInterval, setTimeout and the ajax timeout parameter but it isn't working, it just adds requests to the call stack and after the timeout duration it appends the div 5 times.
Here's the ajax call:
$.ajax({
url: "/wp-admin/admin-ajax.php",
type:"POST",
data: {
action: "my_custom_color",
post_link: post_ID
}, success: function (response) {
$('.color').prepend(response);
},
})
I want to be able to do something like this:
colorsMonoSlider.events.on('indexChanged', () => {
setTimeout(() => {
customizedFunction()
}, 1000);
});
But without filling the call stack (maybe emptying it at each call), the ajax request should only trigger once after the timeout, I can't disable the slider navigation or use async: false because as I said users need to be able to spam click to go through the slider fast.
Any tips welcome, thanks in advance.
You need to cancel both your ajax call and timer functions before invoking again.
Assuming the customized function has the ajax call.
var xhr,timer;
function customizedFunction(){
xhr && xhr.abort();
xhr = $.ajax({
url: "/wp-admin/admin-ajax.php",
type:"POST",
data: {
action: "my_custom_color",
post_link: post_ID
}, success: function (response) {
$('.color').prepend(response);
},
})
}
colorsMonoSlider.events.on('indexChanged', () => {
timer && clearTimeout(timer);
timer = setTimeout(() => {
customizedFunction()
}, 1000);
});
As my title indicates, I need to run a function if any ajax get/post is fired.
I tried using
$(document).ajaxStart(function () {
console.log('a');
});
$(document).ajaxComplete(function () {
console.log('c');
});
but it runs only for the first time.
Later it does not log anything. What am I doing wrong?
I need to do this in chrome extension and on google image search page, so after 100 images it fire a ajax function to get more image data and show on page.
You probably want it to work even if AJAX requests are not made with jQuery with a technique like How to check if HTTP requests are open in browser?
(function() {
var oldOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
console.log('Request went out', arguments);
oldOpen.call(this, method, url, async, user, pass);
}
})();
You might be looking for something like this:
$.ajaxSetup({
success: function(){
callYourFunctionHere();
}
});
OR
$(document).bind("ajaxSend", function(){
alert('ajax fired');
callYourFunctionHere();
});
Hope it works for you.
The ajax method itself can accept functions in beforeSend and complete.
.ajax({
// the rest of your parameters
complete: function(data) {
// do something
}
});
If you do not want to specify these on a per-request basis, you can do so with the `.ajaxSetup' function which modifies the defaults.
.ajaxSetup({
beforeSend: function() {
// custom logic
},
complete: function() {
// custom logic
}
});
When I look at logs with the Charles proxy, I see that the user's submit (POST) doesn't always contain all the form data. Sometimes it is missing the bottom third of the form data, apparently when the AJAX call in the PeriodicalExecuter fires. I'm not absolutely sure about this. Here's roughly how the page script looks:
document.observe("dom:loaded", function() {
...
new PeriodicalExecuter(function(pe) {msgEntryRqst(host_URL, web_sid, pageType, recordNbr);}, delaySecs);
...
}
function msgEntryRqst(host_URL, web_sid, pageType, recordNbr) {
...
new Ajax.Request('/'+host_URL, {
method: 'get',
parameters: {c: 'AJAX_request', ajtype: 'instantMessage', sid: web_sid, pagetype: pageType, record: recordNbr, rnd: Math.random()},
onSuccess: function(response) {
if(response.responseText.length>0) {
...
}
}
}
}
Is there a way to do, for example, DOCUMENT.observe('click', 'myHandler'), perhaps within the "dom:loaded" section, to set a flag when the user has clicked on a save button or navigation tab, to skip one cycle of the AJAX command and thereby not truncate the user's POST?
Sometimes in my application there are many elements loading so I want to show the typical AJAX spinner above the control (or DOM node) with it disabled.
What is the easiest/best way to do that?
Ideally I would like to:
$("#myelement").loading();
$("#myelement").finishloading();
Or even better being able to do AJAX requests directly with the element:
$("#myelement").post(url, params, myfunction);
Being #myelement a regular node or form input.
You could use beforeSend and complete callbacks:
$.ajax({
url: 'script.cgi',
type: 'POST',
beforeSend: function() {
$('.spinner').show();
},
complete: function() {
// will trigger even if request fails
$('.spinner').hide();
},
success: function(result) {
// todo: do something with the result
}
});
Since you're already using jQuery, you may want to look into BlockUI in conjunction with Darin Dimitrov's answer. I haven't used it yet myself as I just came across this today, but it looks decent.
If you're writing a semi-large-ish application and anticipate making many AJAX calls from different places in your code, I would suggest that you either add a layer of abstraction over $.ajax, or create a helper function to avoid having boiler plate for your UI indicator all over the place. This will help you out a lot should you ever need to change your indicator.
Abstraction method
var ajax = function(options) {
$.ajax($.extend(
{
beforeSend: function() {
$.blockUI();
},
complete: function() {
$.unblockUI();
}
},
options
));
};
ajax({
url: 'script.cgi',
type: 'POST',
success: function(result) {
// todo: do something with the result
});
Helper method
var ajaxSettings = function(options) {
return $.extend(
{
beforeSend: function() {
$.blockUI();
},
complete: function() {
$.unblockUI();
}
},
options
);
};
$.ajax(ajaxSettings({
url: 'script.cgi',
type: 'POST',
success: function(result) {
// todo: do something with the result
}
}));
Also, I wouldn't suggest overwriting the $.ajax method itself.
what i've done in the past is, on post pass the element id (a containing div) to a function which replaces it's inner HTML with a loading image, and then in the post back replace it's content again with the updated real content.
If you want to show the spinner every when an ajax call is in progress I think you should use ajaxStart and ajaxStop.
$("#spinner")
.ajaxStart(function(){$(this).show();})
.ajaxStop(function(){$(this).hide();});