I know that in some browsers (IE, Chrome) that changes to the DOM won't take place until after a function is completed. I have read through various suggestions on how to deal with this, but I'm not having any luck. I'm trying to loop through a series of AJAX calls and show progress for each line that is being processed. The code is like this:
for(i=0; i < rowIds.length; i++){
$(rowImage).attr('src', '/images/spinner.gif');
$.ajax({
type: 'GET',
url: ajaxUrl,
async: false,
processData: true,
data: {},
dataType: "json",
success: function(data) {
$(rowImage).attr('src', '/images/success.gif');
}
});
}
I've read several suggestions about trying to insure that the image transformation takes place before proceeding, such as doing this before the AJAX call starts:
var changeImage = function() {
$(rowImage).attr('src', '/images/spinner.gif');
};
$.when(changeImage() ).done( function() {
//run AJAX call
But that doesn't make a difference. The images don't change until after the function is finished executing.
You will note that I have async set to false, and I'm doing that for various reasons. But even without that in place, the issue persists. I've also tried using setTimeOut() as has been suggested, and that doesn't seem to work (And I know that setTimeOut() is meant for async mode, but even in async it doesn't seem to help.)
Jquery:
$.ajax({
type: 'GET',
url: ajaxUrl,
async: false,
processData: true,
data: {},
dataType: "json",
success: function(data) {
$(rowImage).attr('src', '/images/success.gif');
}
});
$(document).ajaxStart(function () {
$(rowImage).attr('src', '/images/spinner.gif');
}).ajaxStop(function () {
});
Related
I Have a 2 JavaScript functions what call one after another. like following.
updateUI(event);
syncCall();
function updateUI(event) {
formSubmitBtn = $(event.target).find('[type=submit]:not(".disabled")');
formSubmitBtn.attr('disabled', 'disabled');
var loadingText = I18n.t('Submitting');
formSubmitBtn.val(loadingText).text(loadingText);
}
function syncCall(){
$.ajax({
async: false,
dataType: 'json',
type: 'GET',
url: '/calls/synccall',
success: function (json) {
userIsSignedIn = json.is_signed_in;
}
});
}
I am updating a UI element before sync ajax call. but UI changes are not showing. When I try to debug the code it works fine.
I can imagine your code is doing something like
var userIsSignedIn;
updateUI(event);
syncCall();
nextThing(userIsSignedIn);
anotherThing();
moreThings();
With a simple change to syncCall - called asyncCall to be not confusing
function asyncCall(cb){
$.ajax({
dataType: 'json',
type: 'GET',
url: '/calls/synccall',
success: function (json) {
cb(json.is_signed_in);
}
});
}
your code re-written:
updateUI(event);
asyncCall(function(userIsSignedIn) {
nextThing(userIsSignedIn);
anotherThing();
moreThings();
});
Note the lack of var userIsSignedIn; required
Really a small change for improved end user experience
a second alternative is to wrap all the code you presented in a function tagged async
async function doThings() {
updateUI(event);
let userIsSignedIn = await ajaxCall(); // see below
nextThing(userIsSignedIn);
anotherThing();
moreThings();
}
and return a Promise from ajaxCall (what was syncCall)
function ajaxCall(){
return $.ajax({
dataType: 'json',
type: 'GET',
url: '/calls/synccall'
}).then(json => json.is_signed_in);
}
Run this through a transpiler (like babel) to produce code that should work on Internet Exploder and similarly "backward" browsers
Summary: In the end you have two choices
Use async:false and have rubbish user experience
embrace asynchrony and write code that befits the 21st century
Call this function beforeSend like as follows
function syncCall(){
$.ajax({
async: false,
dataType: 'json',
type: 'GET',
url: '/calls/synccall',
beforeSend:function(){
updateUI(event);// Call here
}
success: function (json) {
userIsSignedIn = json.is_signed_in;
}
});
}
If above not work try following
updateUI(event);
function updateUI(event) {
formSubmitBtn = $(event.target).find('[type=submit]:not(".disabled")');
formSubmitBtn.attr('disabled', 'disabled');
var loadingText = I18n.t('Submitting');
formSubmitBtn.val(loadingText).text(loadingText);
syncCall();// Try calling here
}
function syncCall(){
$.ajax({
async: false,
dataType: 'json',
type: 'GET',
url: '/calls/synccall',
success: function (json) {
userIsSignedIn = json.is_signed_in;
}
});
}
I am now in javascript, I am trying to display a indictor icon when ajax starts and hide it when it finishes, below is my code:
CSS:
div.ajax-progress {
//some setting and url
}
<body>
<div class="ajax-progress"></div>
</body>
Javascript:
$('#fileToUpload').on('change', function(e) {
var file = e.target.files[0];
var formData = new FormData($('form')[0]);
imageId = cornerstoneWADOImageLoader.fileManager.add(file);
$.ajax({
url: 'loadfile.php',
type: 'POST',
data: formData,
async: false,
dataType: 'json',
timeout : 60000,
beforeSend :function(){
$(".ajax-progress").show();
},
success: function (html) {}
$(".ajax-progress").hide();
//doing something}
});
});
but nothing happens, any idea? appreciated.
Maybe if you put $(".ajax-progress").show(); before the call of ajax $.ajax({}); and them hide it in the succes.
I don't know if that's the same to what you have in your code but you commented out the success closing bracket }
you can also use console.log() or alert() to see what's going on in your code.
Try rewriting your ajax as below:
$.ajax({
url: 'loadfile.php',
type: 'POST',
data: formData,
async: false,
dataType: 'json',
timeout : 60000,
beforeSend :function(){
//do something
},
success: function (html) {
//doing something
}
});
$(document).ajaxStart(function() {
$(".ajax-progress").show();
});
$(document).ajaxStop(function() {
$(".ajax-progress").hide();
});
This will show and hide $(".ajax-progress") in all your ajax requests within the application.
I have function making multiple AJAX request with jQuery like:
function() {
$.ajax({
url: "/url",
data: {
params: json_params,
output: 'json'
},
async: false,
success: function(res) {
data1 = res
}
});
$.ajax({
url: "/url",
data: {
params: json_params,
output: 'json'
},
async: false,
success: function(res) {
data2 = res;
}
return data1 + data2;
});
}
While this function is running and data is loading I want to display a loading image without blocking it.
I have tried showing the loading icon using ajaxSend ajaxComplete, but does not work, since I have multiple ajax calls.
I also tried showing the loading at the beginning of the function and hiding at the end of the function, but failed.
How to do this?
How exactly did you try loading? Using the ajaxStart/ajaxStop events on the elements is one way to accomplish what you want. It could look like this:
$('#loadingContainer')
.hide() // at first, just hide it
.ajaxStart(function() {
$(this).show();
})
.ajaxStop(function() {
$(this).hide();
})
;
Maybe this helps you, I often used this before and it works like a charm..
I think the answer is really a combination of several of these. I would begin with ajax start to show the loading image at 0 (or whereever you want the start to be). Then I would use a callback function to increment the loading bar and repaint it.
For example
//when ajax starts, show loading div
$('#loading').hide().on('ajaxStart', function(){
$(this).show();
});
//when ajax ends, hide div
$('#loading').on('ajaxEnd', function(){
$(this).hide();
});
function ajax_increment(value) {
//this is a function for incrementing the loading bar
$('#loading bar').css('width', value);
}
//do ajax request
$.ajax({
url:"", //url here
data: {params:json_params,output:'json'},
async: false,
success: function (res) {
data1=res
ajax_increment(20); //increment the loading bar width by 20
}
});
$.ajax({
url:"", //url here
data: {params:json_params,output:'json'},
async: false,
success: function (res) {
data1=res
ajax_increment($('loading bar').css('width') + 10); // a little more dynamic than above, just adds 10 to the current width of the bar.
}
});
You could try something like this: Define a callback with a counter, and the callback hides the image after it's been called the required number of times.
showLoadingImage();
var callbackCount = 0;
function ajaxCallback() {
++callbackCount;
if(callbackCount >= 2) {
hideImage();
}
}
$.ajax({
url:"/url",
data: {params:json_params,output:'json'},
async: false,
success: function (res) {
data1=res
ajaxCallback();
}
});
$.ajax({
url:"/url",
data: {params:json_params,output:'json'},
async: false,
success: function (res) {
data2=res;
ajaxCallback();
}
});
That's only necessary for asynchronous calls, though. The way you're doing it (all your AJAX calls are synchronous), you should be able to just call hideImage() before returning at the end of your outer function.
You should be able to bind to the start and then end with the following:
$('#loading-image').bind('ajaxStart', function() {
$(this).show();
}).bind('ajaxStop', function() {
$(this).hide();
});
Or you could use beforeSend and on Complete
$.ajax({
url: uri,
cache: false,
beforeSend: function() {
$('#image').show();
},
complete: function() {
$('#image').hide();
},
success: function(html) {
$('.info').append(html);
}
});
I have a mobile app using mostly JQuery Mobile. I have an ajax function using POST and I can't seem to get anything to effect the UI when I fire the click event. I tried setting
$('#cover').show();
as the very first thing in the function then I do some basic things like document.getElementById('user') etc to set some variables and check input, but as long as the ajax function is there it won't show the div or even the spinner from JQ Mobile. Unless I debug and step through the code then the spinner and div show up fine. I tried setTimeout and putting it in the beforeSend area of the ajax call. Everything works fine otherwise. It seemed to work a little better with GET I'm not sure if that has anything to do with it or not.
$.ajax({
cache: false,
type: "POST",
async: false,
url: urlString,
data: jsonstring,
contentType: "application/json",
dataType: "json",
success: function (data) {
JSONobj = JSON.parse(data);
},
beforeSend: function(xhr){
//console.log('BeforeSend');
},
complete: function (xhr) {
//console.log('Complete');
},
error: function (xhr, status, error) {
console.log(error);
}
});
You could use the Ajax Global handlers to handle this:
$(document).
.ajaxStart(function(){
$('#cover').show();
})
.ajaxStop(function(){
$('#cover').hide();
});
This way you don't have to worry about showing/hiding the overlay on individual Ajax calls.
Try this
$("#someButton").click(function(e){
e.preventDefault() //if you want to prevent default action
$('#cover').fadeIn(100,function(){
$.ajax({
url: "someurl",
data: "Somedata",
contentType: "application/json",
dataType: "json",
},
success: function (data) {
JSONobj = JSON.parse(data);
$('#cover').fadeOut(100);
},
complete: function (xhr) {
$('#cover').fadeOut(100);
}
});
});
});
I am trying to show a loading image while my ajax call is running, however using the beforeSend attribute is not changing my result area.
$.ajax({
url: "/answer_checker.php",
global: false, type: "POST",
data: ({...clipped...}),
cache: false,
beforeSend: function() {
$('#response').text('Loading...');
},
success: function(html) {
$('#response').html(html);
}
}
Thanks in advance.
I had a similar problem. To resolve my issue, I replaced the .text, in the beforeSend section, with .html and created a html tag to insert into the element that holds my status. The success function did not replaced the content created by the .text() function but it did replace content created by the .html() function.
$.ajax({
url: "/answer_checker.php",
global: false, type: "POST",
data: ({...clipped...}),
cache: false,
beforeSend: function() {
$('#response').html("<img src='/images/loading.gif' />");
},
success: function(html) {
$('#response').html(html);
}
}
I have a solution, it may not be the best way to do it but it has worked in this case.
$('input').keyup(function () {
$('#response').text('loading...');
$.ajax({
url: "/answer_checker.php",
global: false, type: "POST",
data: ({...clipped...}),
cache: false,
success: function(html) {
$('#response').html(html);
}
});
});
By setting the resonce content before calling the ajax function it remains showing the loading text until the ajax call updates the same content.
Thanks to everyone who took the time to answer.
Alan
You are were missing a comma after cache: false
You can also use the following:
$('#tblLoading').ajaxStart(function() { $(this).show(); });
$('#tblLoading').ajaxComplete(function() { $(this).hide(); });