I have a following ajax operation that is intended to (1) show spinner gif before sending ajax request, and after after the request is complete, (2) hide the gif and 3 display appropriate alert messages.
Finally (4) reload the page.
Here's the code:
$.ajax({
url: rUrl,
data: {
id: rID,
requisitionStatus: rStatus,
comment: rComment
},
type: "POST",
cache: false,
beforeSend: function() {
$("#requisitionStatusDialog").dialog('close');
$('#ajax_loader_my').show();
},
success: function(data, resp) {
var json = data;
var obj = JSON && JSON.parse(json) || $.parseJSON(json);
if (obj.status == "success") {
alert('Success! ' + obj.message);
location.reload();
} else if (obj.status == "error") {
alert('Error!' + obj.message);
}
},
error: function(data, resp) {
$("#updateDialog").dialog('close');
console.log(resp);
},
complete: function() {
$('#ajax_loader_my').hide();
}
});
But in this case, alert pops up first while the spinner gif still shows up, and reloads the page after clicking OK.
I even tried hiding the gif in success callback itself instead of using complete:
success: function(data, resp) {
var json = data;
var obj = JSON && JSON.parse(json) || $.parseJSON(json);
if (obj.status == "success") {
$('#ajax_loader_my').hide();
alert('Success! ' + obj.message);
location.reload();
} else if (obj.status == "error") {
alert('Error!' + obj.message);
}
},
Both gives the same result.
The reason your alert pops up before the spinner is hidden is the success code runs before complete which hides the spinner. The reason it reloads is because after the alert you send location.reload();
Check that $('#ajax_loader_my').hide(); is actually hiding the spinner. The element that is or contains the spinner in your html must be have its id set to ajax_loader_my.
If you open Chrome or Firefox Dev tools you should be able to send $('#ajax_loader_my').hide() and see what happens.
Rewrite the code this way, this will put your alert and location related code in event queue which will run when it will be free.
if(obj.status=="success") {
$('#ajax_loader_my').hide();
setTimeout(function(){
alert('Success! '+obj.message);
location.reload();
},0);
}
Hi you should try to use promises here is the documentation Jquery promises, I made this on the fly it can have some errors but is just an example:
$( function() {
function AjaxCall(rID,rStatus,rComment){
return $.ajax({
url: 'request.php',
data: {
id: rID,
requisitionStatus: rStatus,
comment: rComment
},
type: "POST",
cache: false,
beforeSend: function() {
$("#requisitionStatusDialog").dialog('close');
$('#ajax_loader_my').show();
}
})
}
$( "#requisitionStatusDialog" ).dialog();
$("#yourbuttonInputId").on('click',function(event) {
AjaxCall().done(function(data,response){
var obj = JSON.parse(data);
if (obj.status == "success") {
alert('whe are on done!');
}
}).fail(function(data,response){
$("#updateDialog").dialog(' close');
}).always(function(data){
if(confirm('You have finished the request. Click OK if you wish to continue ,click Cancel to reload the page.'))
{
$('#ajax_loader_my').hide();
$("#requisitionStatusDialog").dialog('open');
}else{
location.reload();
}
});
});
} );
EDIT: Check this jsfiddle it will guide you to elaborate your code
Hope it Helps
I would rather suggest to use an empty div or span with an Id.
Than display success in the html of that div.
For Example:
$('#ajax_loader_my').hide();
setTimeout(function () {
$('#successDiv').html('Success! ' + obj.message);
location.reload();
}, 2000);
Related
I'm doing an Ajax query that pulls back a JSON array filled with ~50 urls to images. I then use a forEach on the array to produce a <div> nested with other <div>, with one of those <div> holding an <img> element in where I set the src equal to the current url in the forEach iteration.
The catch is that some of the urls are dead, and result in broken <img> elements ( you know, with the little images of a ripped file?). So what I do is, during the iterations, when I create my <img> element, I set the onerror attribute equal to "$(this).closest('.gramDiv').remove()", which attempts to delete a certain <img> parent element and all of that parent's childrens. This works, but I feel like it's kinda hacky, and not best practice. Is there more standardized way of doing this?
$(document).ready(function(){
console.log("Ready");
function adder(data,status){
data.forEach((url,index)=>{
let attrObj = {
src: url,
alt: 'photo ' + index,
onerror: "$(this).closest('.targetDiv').remove()"
};
let img = $('<img>').attr(attrObj);
let targetDiv = $('<div></div>').addClass('target');
let picDiv = $('<div></div>').addClass('picDiv').append(img);
let component = targetDiv.append(picDiv);
$('#bodyDiv').append(component);
})
}
$.ajax({
url:'https:/blahblahblah.json',
dataType: 'json',
success: adder,
timeout: 3000,
error: function(){ alert('error retrieving')}
});
})
You can try to use this code
$("<img/>")
.on('load', function() { console.log("image loaded correctly"); })
.on('error', function() { console.log("error loading image"); })
.attr("src", $(originalImage).attr("src"))
;
From here
Thanks to #SabirAmeen and this link for this answer.
Basically, within the forEach block, you want to run another ajax call on the URL of the current iteration, and retrieve it's status, which indicates whether it's working or broken. In my case, a working status is 200, and anything else I consider broken.
I've simplified my code from above, but it still illustrates the point:
$(document).ready(function(){
console.log("Ready");
//event.preventDefault();
console.log("pressed");
function adder(data,status){
data = data.reduce(function(a,b){
if(!a.includes(b)) a.push(b);
return a;
},[]);
data.forEach((url,index)=>{
UrlExists(url, function(status){
if(status === 200){
// file was found
console.log('found:',status);
let img = $('<img>').attr('src',url);
$('body').append(img);
}
else {
// do nothing
console.log('not found:',status);
}
});
})
}
function UrlExists(url, cb){
jQuery.ajax({
url: url,
dataType: 'text',
type: 'GET',
complete: function(xhr){
if(typeof cb === 'function')
cb.apply(this, [xhr.status]);
}
});
}
$.ajax({
url:'https://yaddayadda.json',
dataType: 'json',
// success: adder,
success: adder,
//complete: remover,
timeout: 3000,
error: function(){ alert('error retrieving data fam')}
});
})
Is it possible to tell if a jquery ajax request has been going on for more than a certain length of time? I would like to prompt users of my site if the request has been going on for 10 seconds to reload and retry, but I cant find anything in the documentation to meet my request.
Try setting timeout property and get the error handler parameter. The possible values are
"timeout", "error", "abort", and "parsererror"
$.ajax({
url: "/ajax_json_echo/",
type: "GET",
dataType: "json",
timeout: 1000,
success: function(response) { alert(response); },
error: function(x, t, m) {
if(t==="timeout") {
alert("got timeout");
} else {
alert(t);
}
}
});
So for all ajax requests in your site... you should do something like this...
$.ajaxSetup({
beforeSend: function(jqXHR, settings){
/* Generate a timer for the request */
jqXHR.timer = setTimeout(function(){
/* Ask the user to confirm */
if(confirm(settings.url + ' is taking too long. Cancel request?')){
jqXHR.abort();
}
}, 10000);
}
});
Set a timeout and then cancel it once it ajax call completes.
var timer = setTimeout(function() {
alert('Too long!');
}, 10000);
$.getJSON(url, function() {
clearTimeout(timer);
});
I'm a little new to jQuery framework and while using AJAX with normal javascript I used readyState() function to display a loading gif image. But, I don't know how to use that in jQuery .post() method. Was it possible to add a class until it finishes loading? If so, please give a code sample. My function is similar to this:
$.post("verify.php",{
username: u,
password: p
},function(r) {
if(r == 1) {
$(".elmt").addClass("loading");
} else if (r == 0) {
location.href = 'http://localhost';
}
});
I always prefer using $.ajax for things like this as it has more options than the shortcuts :
$.ajax({
type: 'POST',
url : 'verify.php',
data: {
username: u,
password: p
},
beforeSend: function () {
$(".elmt").addClass("loading"); // add loader
}
}).always(function() { // always executed
$(".elmt").removeClass("loading"); // remove loader
}).done(function(r) { // executed only if successful
if (r == 0) {
location.href = '/';
}
});
Just call the addClass before the $.post() and be done with it
$(".elmt").addClass("loading");
$.post("verify.php", {
username: u,
password: p
}, function (r) {
location.href = 'http://localhost';
});
You could fire a custom event before starting your AJAX request.
Then in your success function, fire another to stop.
Or if you just want the loading animation:
$(".elmt").addClass("loading");
$.post("verify.php",{
username: u,
password: p
},function(r) {
$(".elmt").removeClass("loading");
// etc...
});
There is a global way to do this using ajaxStart() and ajaxStop(). See How to show loading spinner in jQuery?
If you need to do for all your requests. You could try:
$(document).ajaxStart(function(){
$(".elmt").addClass("loading");
});
$(document).ajaxStop(function(){
$(".elmt").removeClass("loading");
});
But it's not so cool to always display the loading when the request takes little time as it will cause the screen flicking. Try:
var timer;
$(document).ajaxStart(function(){
timer = setTimeout(function(){
$(".elmt").addClass("loading");
},1500);
});
$(document).ajaxStop(function(){
clearTimeout(timer);
$(".elmt").removeClass("loading");
});
By adding a timer, only requests that take longer than 1.5 seconds should be considered long and display a loading icon.
As you see on code below you can do your work on different results of post method
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.post("example.php", function() {
alert("success");
})
.done(function() { alert("second success"); })
.fail(function() { alert("error"); })
.always(function() { alert("finished"); });
// perform other work here ...
// Set another completion function for the request above
jqxhr.always(function(){ alert("second finished"); });
I have a procedure running on a timeout to load data in the background:
(function getSubPage() {
setTimeout(function() {
if (cnt++ < pagelist.length) {
loadSubPage(pagelist[cnt]);
getSubPage();
}
}, 500);
})();
In loadSubPage() I'm making $.ajax() calls:
function loadSubPage(page) {
if (typeof(initSubPages[page]) === "undefined") {
$.ajax({
type: "POST",
url: '/Main/GetPageData',
data: { page: page },
success: function (returndata) {
// ...
},
error: function() {
alert("Error retrieving page data.");
}
});
initSubPages[page] = true;
}
}
The problem I'm having is that the error handler is being hit when the user navigates away if any ajax requests are open. I'm trying to get around this by .stop()ing the requests on window.onbeforeunload, but I'm not sure what object to call .stop() on?
jQuery exposes the XMLHttpRequest object's abort method so you can call it and cancel the request. You would need to store the open request into a variable and call abort().
activeRequest = $.ajax({...
and to stop it
activeRequest.abort()
Abort Ajax requests using jQuery
This should come in handy.. You have a jQuery method for doing just that.
The $.ajax returns XMLHTTPRequestObject which has .abort function. This function will halt the request before it completes.
var xhr = $.ajax({ /*...*/
..
..
/* Later somewhere you want to stop*/
xhr.abort();
Read more: How to cancel/abort jQuery AJAX request?
Here is the solution I used based on the feedback:
window.onbeforeunload = function() {
for (page in ajaxing) {
if (ajaxing[page] != null)
ajaxing[page].abort();
}
};
var ajaxing = {};
function loadSubPage(page) {
if (typeof(initSubPages[page]) === "undefined") {
var ajaxRequest = $.ajax({
type: "POST",
url: '/Main/GetPageData',
data: { page: page },
success: function (returndata) {
// ...
},
error: function() {
alert("Error retrieving page data.");
},
complete: function() {
ajaxing[lot] = null;
}
});
ajaxing[page] = ajaxRequest;
initSubPages[page] = true;
}
}
Is there a way to check if there's ajax request in progress?
Something like:
if ( $.ajax.inProgress ){ do this; } else { do that; }
yes there is
$.ajax({
type: 'get',
url: 'url',
data: {
email: $email.val()
},
dataType: 'text',
success: function(data)
{
if(data == '1')
{
$response.attr('style', '')
.attr('style', "color:red;")
.html('Email already registered please enter a different email.');
}
else
{
$response.attr('style', '')
.attr('style', "color:green;")
.html('Available');
}
},
beforeSend: function(){
$email.addClass('show_loading_in_right')
},
complete: function(){
$email.removeClass('show_loading_in_right')
}
});
the beforeSend will do the process you need to do when the ajax request has just started and complete will be called when the ajax request is complete.
documentation
To abort ajax request,
Use
if($.active > 0){
ajx.abort();//where ajx is ajax variable
}
To continue running ajax request,
Use
if($.active > 0){
return;
}
You should basically set a variable on top of script set to false and on ajax initiate set it to true and in the success handler set it to false again as described here.
You might like this:
$(document).ready(function() {
var working = false;
$("#contentLoading").ajaxSend(function(r, s) {
$(this).show();
$("#ready").hide();
working = true;
});
$("#contentLoading").ajaxStop(function(r, s) {
$(this).hide();
$("#ready").show();
working = false;
});
$('#form').submit(function() {
if (working) return;
$.post('/some/url', $(this).serialize(), function(data){
alert(data);
});
});
});
If you are in full control of the javascript code you could increment a variable whenever you start an ajax request and decrement it when the request completes (with success, failure or timeout). This way you always know if there is a request in progress.