I'm trying to show spinner and overlay before sending an ajax request. But The onclick event directly sending the ajax request without showing the overlay and spinner. Can anyone point me out what i'm doing wrong! here is my code
$(document).ready(function() {
$(".refreshBtn").on('click', function() {
$("#overlay").css('display', 'block');
$(".spinner").css('display', 'block');
TableDataContent();
});
function TableDataContent() {
$(".all_tab_content").html('');
var tableDiv = '<div id="Leaderboard" class="tabcontent"><table class="table-striped"><tbody></tbody></table></div>';
$(".all_tab_content").append(tableDiv);
var tableBody = $('#Leaderboard tbody');
$.ajax({
type: 'get',
url: 'https://sheets.googleapis.com/v4/spreadsheets/{SHEET_ID}/values/Leaderboard?key={API_KEY}',
async: false,
success: function(response) {
}
});
$("#overlay").css('display', 'none');
$(".spinner").css('display', 'none');
}
});
You are hiding the spinner before ajax finishes put hide them from inside the complete callback so they can be hidden even when the ajax fails.
$.ajax({
type: 'get',
url: 'https://sheets.googleapis.com/v4/spreadsheets/{SHEET_ID}/values/Leaderboard?key={API_KEY}',
async: false,
success: function(response) {
},
complete: function(xhr, textStatus){
$("#overlay").css('display', 'none');
$(".spinner").css('display', 'none');
}
});
Your spinner does not show because AJAX requests are asynchronous. It means that it will be executed while the script continue to be executed too.
To correct that, move instructions which hide the overlay and the spinner in the success callback of your AJAX.
Right now you are hiding .spinner and #overlay without waiting for ajax to complete. Ajax's success callback happening when data is received, this is exactly the moment you want hiding .spinner and rest.
$.ajax({
type: 'get',
url: 'https://sheets.googleapis.com/v4/spreadsheets/{SHEET_ID}/values/Leaderboard?key={API_KEY}',
async: false,
success: function(response) {
$("#overlay").css('display', 'none');
$(".spinner").css('display', 'none');
// rest of your business
}
});
The problem is entirely due to your use of async: false. It's incredibly bad practice as it prevents the browser from being updated while the request is in progress. It's for this reason you never see the UI changes.
To fix this, remove async: false and instead work with the async callbacks of $.ajax(), like this:
$(function() {
$(".refreshBtn").on('click', function() {
TableDataContent();
});
function TableDataContent() {
var $indicators = $("#overlay, .spinner").show(); // show the loading indicator when the request starts...
var tableDiv = '<div id="Leaderboard" class="tabcontent"><table class="table-striped"><tbody></tbody></table></div>';
$(".all_tab_content").empty().append(tableDiv);
var $tableBody = $('#Leaderboard tbody');
$.ajax({
type: 'get',
url: 'https://sheets.googleapis.com/v4/spreadsheets/{SHEET_ID}/values/Leaderboard?key={API_KEY}',
success: function(response) {
// work with the response here...
},
complete: function() {
$indicators.hide(); // hide the loading indicator when the request ends
}
});
}
});
Note the use of empty(), show() and hide() here.
You also presume you need to change {SHEET_ID} and {API_KEY} in the URL to their actual values - presuming that's not just redacted data in the question.
Related
I have a page that makes different ajax calls based on what element one clicks on. There are four IDs and only one should be visible at any given moment. My problem comes when I load new ajax content into a div - I get a flash for a very brief second of the previous content. Here is one of my functions for one of the calls (they are all essentially the same). At the beginning of the function I hide everything. Then after the ajax has loaded I show the relevant div. I'm confused about why this would not work. There should be no flash, since all the div are hidden, right?
$('body').on("click", "#answer-submit", function() {
$('#games, #location, #question, #answer').css('display' , 'none');
var theAnswer = $('#challenge-answer').val();
$.ajax({
type: "POST",
url: "ajax/answer.php",
data: { answer : theAnswer },
dataType: "html",
success: function(msg){
if(parseInt(msg)!=0) {
$('#answer').html(msg);
}
}
});
$('#answer').css('display' , 'block');
});
The problem is an asynchronous request is going to happen asynchronously. In other words, your success function is going to be called after $('#answer').css('display' , 'block'); (it is a race condition but it's practically guaranteed). The solution is simple -- move $('#answer').css('display' , 'block'); into the success function:
$('body').on("click", "#answer-submit", function() {
$('#games, #location, #question, #answer').css('display' , 'none');
var theAnswer = $('#challenge-answer').val();
$.ajax({
type: "POST",
url: "ajax/answer.php",
data: { answer : theAnswer },
dataType: "html",
success: function(msg){
if(parseInt(msg)!=0) {
$('#answer').html(msg);
$('#answer').css('display' , 'block');
}
}
});
});
You can even chain it like so:
if (parseInt(msg) != 0) {
$('#answer')
.html(msg)
.css('display', 'block');
}
I have this JQuery code:
$(function(){
$('input#SearchGo').on('click', function(){
var searchid = $('input#search').val();
var dataString = 'search='+ searchid;
$.ajax({
type: "POST",
url: "tickets.php",
data: dataString,
cache: false,
success: function(html) {
$("#result").html(html).show();
}
});
return false;
});
});
that does a live search and posts data to a PHP page.
On every page i have a div with an id of overlay with a loading image while the page loads, then this code:
$(window).load(function(){
// PAGE IS FULLY LOADED
// FADE OUT YOUR OVERLAYING DIV
$('#overlay').fadeOut();
});
removes the overlay div once the page has loaded.
when i run the search query, the overlay div doesnt fadeOut at all, i tried adding $('#overlay').fadeOut(); within the success part of my function but it doesnt fadeOut the div.
UPDATE:
here is the HTML for the loading / overlay div
<div id="overlay" class="overlay">
<img src="images/integra_loading.gif" alt="Loading" width="12%" style="margin-top:15%;" />
<br /><br />
<h1>Loading...</h1>
</div>
$(function(){//this says the dom is ready
$('#overlay').fadeOut();
});
alternatively
$(document).on("ajaxComplete", function(){
$('#overlay').fadeOut();
});
Don't hide your ajaxloader with a function that is called from the html script wich is loaded through the ajax request. just show the loader before the request and hide it before replacing the html content with your response.
function loader(){
this.id = '#overlay'
};
loader.prototype.show = function(){
$(this.id).fadeIn();
};
loader.prototype.hide = function(){
$(this.id).fadeOut();
};
loaderObj = new loader();
$('.list').live('click', function() {
loaderObj.show();
$.ajax({
type: "GET",
url: "http://echo.jsontest.com/uid/12345/value/nuno_bettencourt",
cache: false,
dataType: "json",
success: function(json) {
// setTimeout only to delay the response and let the loader do his thing ;)
setTimeout(function(){
loaderObj.hide();
$('#ajaxResult').html("UID=" + json.uid + "\nName=" + json.value);
}, 2000);
}
});
i made you a small fiddle example http://jsfiddle.net/358Fz/1/
after doing your $.ajax, add a done. in that done, do the fadeout!
$.ajax({
...
}).done(function(){
$('#overlay').fadeOut();
});
you can add a .fail for when it fails, etc. see: http://api.jquery.com/jquery.ajax/
Just define the loader variable outside of your click event and then use it where needed. There will be less overhead if you only have to traverse the DOM once to locate the loader element. You can also change the on event to just a click event to save a few key strokes unless you need to delegate the event to another element. Also, you don't need to look up $(input#search) since ID's are unique. Removing the variable selector and just looking up the ID will be more efficient.
$(function() {
var $loader = $('#overlay');
$('.list').click(function(){
$loader.fadeIn();
$.ajax({
type: "GET",
url: "http://time.jsontest.com/",
dataType: 'json',
cache: false,
success: function(json) {
$loader.fadeOut();
$("#axajResponse").html('<b>Current Time:</b> ' + json.time).show();
}
});
return false;
});
});
In the above example I'm getting back the current time so that you can see the response change on each click event.
Here is an example: http://jsfiddle.net/bradlilley/jLG4g/
I have this ajax request:
$.ajax({
type: "POST",
dataType: "json",
data: dataString,
url: "app/changeQuantity",
success: function(data) {
$('#table').append('<tr><td><a id="uid">click</a></td></tr>');
});
as you can see it makes new row in #table. But this new objects made by ajax are not accessible from next functions. Result from ajax is not a regullar part of DOM, or what is the reason for this strange behavior?
$('#uid').on('click', function () {
alert('ok');
});
Use event delegation:
$(document).on('click','#uid', function () {
alert('ok');
});
Note that ajax calls are asynchronous. So whatever you do with the data you need to do it in a callback within the success function (that is the callback which is called when the ajax call returns successfully).
Jquery on doesn't work like that. Use have to give a parent which not loaded by ajax, and the specify ajax load element like this
$('#table').on('click','#uid' ,function () {
// what ever code you like
});
Is simple and complex at the same time. Simple to solve but complex if you are getting started with javascript...
Your event handler - onclick is being fired and bound to an object that doesnt yet exist.
So when you append the object to the #table, you need to set up your click handler as the object now exists.
So in your success part of the ajax return add the click handler event there.
success: function(data) {
$('#table').append('<tr><td><a id="uid">click</a></td></tr>');
$('#uid').on('click', function () {
alert('ok');
});
});
Or how about you make it dynamic and create a function to do it for you.
function bindClick(id) {
$('#' + id).click(function() {
//Do stuff here
console.log('I made it here' + id);
});
}
Then:
success: function(data) {
$('#table').append('<tr><td><a id="uid">click</a></td></tr>');
bindClick(uid);
});
}
This is a super contrived example but you get the idea you just need to make the rest of it dynamic as well. for example some name and counter generated id number: id1, id2, id3...
Try it like this, add this $('#uid').on('click', function () { into the success
$.ajax({
type: "POST",
dataType: "json",
data: dataString,
url: "app/changeQuantity",
success: function(data) {
$('#table').append('<tr><td><a id="uid">click</a></td></tr>');
$('#uid').on('click', function () {
alert('ok');
});
});
});
the problem is that when I click on .personalized class it does not have both #loading_personalized and #divPersonalized so it takes the AJAX call ..and as soon as I click again on .personalized in time the id #loading_personalized is showing up it hides but the previous AJAX call is not cancelled yet so it executes and shows #divPersonalized, but I want that at the time the #loading_personalized is showing up and I click on .personalized the previous AJAX call should also cancel..
here is my code......
$(document).ready(function(){
$(".Personalized").click(function(){
if($("#divPersonalized").is(':visible')){
$('#triangle-personalized').hide();
$("#divPersonalized").hide();
}
else if($('#loading_personalized').is(':visible'))
{
$('#loading_personalized').hide();
//if this event is true, abort previous ajax call here
}
else {
$.ajax({
type:"POST",
url:"personalized.php",
cache:false,
beforeSend: function(){
$('#loading_personalized').show();
$('#triangle-personalized').show();
},
complete: function(){
$('#loading_personalized').hide();
},
success: function(html){
$("#divPersonalized").html(html).show();
}
});
}
});
You need to store jQuery ajax object and then call abort()
myAjaxCall = $.ajax({
type:"POST",
url:"personalized.php",
cache:false,
beforeSend: function(){
$('#loading_personalized').show();
$('#triangle-personalized').show();
},
complete: function(){
$('#loading_personalized').hide();
},
success: function(html){
$("#divPersonalized").html(html).show();
}
});
if($('#loading_personalized').is(':visible'))
{
$('#loading_personalized').hide();
myAjaxCall.abort();
}
I want to show a div with a loading animation over my page while the page loads some XML content. Once its loaded, I want to hide this div. How can I go about doing this?
$.ajax({
url: '/test.xml',
beforeSend: function(XMLHttpRequest) {
// Show the div before sending the request
$('#load').show();
},
complete: function(XMLHttpRequest, textStatus) {
// Hide the div no matter if the call succeeded or not
$('#load').hide();
},
success: function(xml) {
// if the request succeeds do something with the received XML
}
});
$.ajax({
type: "GET",
url: "your.xml",
dataType: "xml",
beforeSend: function() {
$('#div').fadeIn();
},
success: function(xml) {
// example for parsing xml
$(xml).find('YOUR_XML_TAG').each(function(){
// append xml to page HERE
});
},
complete: function() {
$('#div').fadeOut();
}
});
#cballou Your code will leave '#div' "up", if $.ajax() has not suceeded for any of numerous possible reasons.
Almost right ;)
Never under-estimate the importance of removing redundant $() calls. So ...
//all of this is inside some closure or function
var $blanket = $("#div") ;
// check if after last call, something has possibly removed your '#div'
// throw if false
ASSERT( $blanket.length === 1 ) ;
$.ajax({
type: "GET",
url: "your.xml",
dataType: "xml",
beforeSend: function() { $blanket.fadeIn();
},
success: function(xml) {
// example for parsing xml
$(xml).find('YOUR_XML_TAG').each(function(){
// append xml to page HERE
});
},
complete: function() { $blanket.fadeOut();
}
});
--DBJ
I would use the onbeforeunload event fired when the page URL changes, to create an overlay div with opacity at 0.5, which will be replaced by the new content when the page is loaded.