Implementing the spinner itself isn't that hard, but we found that quick responses from the server caused visual artifacts flickering up because the spinner was only visible for a few milliseconds (probably roughly 30ms).
The solution we chose to implement looks like this:
- before triggering the AJAX request, schedule the code that loads the spinner 150ms into the future
- if the AJAX request returns and the spinner did not materialize yet, cancel the scheduled code
- if the AJAX request returns and the spinner was materialized, schedule the code to hide the spinner 200ms into the future
We implemented this with MochiKit and here is some sample code:
var expansion_element = $('mydivcontainingstuff');
var spinner_loader = MochiKit.Async.callLater(0.15, function() {And here's the CSS:
MochiKit.DOM.addElementClass(expansion_element, 'loading');
MochiKit.DOM.addElementClass(expansion_element, 'loading-spinner');
spinner_loader = null;
});
d = MochiKit.Async.doSimpleXMLHttpRequest(ajax_url);
d.addCallback(function(result){
$('mystuffdivcontainingstuff').innerHTML = result.responseText;
if (spinner_loader != null ) {
spinner_loader.cancel();
} else {
MochiKit.Async.callLater(0.2, function() {
MochiKit.DOM.removeElementClass(expansion_element, 'loading-spinner');
MochiKit.DOM.removeElementClass(expansion_element, 'loading');
});
}
.loading-spinner {
width: 100px;
height: 100px;
margin-left: auto !important;
margin-right: auto !important;
background-image: url(ajax-loader.gif);
background-repeat: no-repeat;
background-position: 50% 50%;
}
.loading * {
display: none;
}