i have the following jquery code. basically - it takes a value from an anchor - and displays a sub-menu content below it. this works perfectly.
$(function(){
$('.plus').live('click', function(event){
event.preventDefault();
$(this).addClass('lower');
var existingPath = $(this).attr('rel');
GetSubs(this, existingPath);
$(this).removeClass('plus').addClass('open'); //.delay(10000).removeClass('lower');
});
function GetSubs(IDclicked, existingPath){
var dataString;
dataString = 'lang=<%=Lang%>&rel=[' + existingPath + ']';
$.ajax({
type: "GET",
url: "/includes/getSubCatMenuLinks.asp",
data: dataString,
success: function(data) {
$(data).insertAfter(IDclicked);
},
error: function(obj,msg) {
alert('*** Error! ***\n\n'+msg);
}
});
}
});
what i would like to do - is have a a "loading" icon showing, while the content is loading - and then remove it when done.
displaying it is fine - thats whats done in the line
$(this).addClass('lower');
when a few lines down, i try remove that class - but the movemext is so fast - that the loading icon doesnt even show. ie - the ajax content hasnt appeared yet, but the jquery code has already loaded the class, loaded the ajax (somewhere) and then removed the class - so the loading icons doesnt even display.
i tried using the delay method - to have it removed a seconds or a few later - but it doesnt work.
any help appreciated!
thanks!
2 Answers 2
As already said, .delay only works with animation methods. Simply remove the class when the Ajax request completed. To keep your code decoupled, make use of the deferred object returned by $.ajax and pass a callback to the .always method [docs]:
var $this = $(this).addClass('lower');
// ...
// or GetSubs(this, existingPath).done if you only want to remove the loader
// when the call was successful. Use .fail to handle error cases.
GetSubs(this, existingPath).always(function() {
$this.removeClass('lower');
// or
// $this.removeClass('plus').addClass('open').removeClass('lower');
// not quite sure when exactly you want to remove / add which classes
});
// ...
function GetSubs(IDclicked, existingPath){
// ...
return $.ajax({ // <- return the $.ajax return value
// ...
});
}
3 Comments
.done instead of .always if I would like to only execute something on the success of the ajax call?delay() only works with animations, and not on functions like removeClass, for that you'll need a timeOut. Not only that, but the Ajax call is asynchronous, so your class is removed instantly and does not wait for the Ajax call to finish.
You could always do:
$(function(){
$(document).on('click', '.plus', function(e){
e.preventDefault();
var self = this,
existingPath = $(this).attr('rel');
$(self).addClass('lower');
GetSubs(self, existingPath, function() { //added callback
setTimeout(function() { //and a one second delay
$(self).removeClass('lower');
}, 1000);
});
});
function GetSubs(IDclicked, existingPath, callback){
var dataString = 'lang=<%=Lang%>&rel=[' + existingPath + ']';
$.ajax({
type: "GET",
url: "/includes/getSubCatMenuLinks.asp",
data: dataString,
success: function(data) {
$(data).insertAfter(IDclicked);
},
complete: function() {
callback.call(); //callback function is called when ajax is finished
},
error: function(obj,msg) {
alert('*** Error! ***\n\n'+msg);
}
});
}
});
This waits for the ajax call to finish, then waits one second, and then does the class stuff. Usually a timer just to show off your nice spinner is considered bad UI, so I would just keep the callback function.
successcallback of yourGetSubsfunction.