If you want a 'youtube-like' loader for your AJAX application that actually represents legitimate page loading progress, consider the following solution (based on Nathan Srivi's answer):
In your .ajax()
method:
$.ajax
(
{
...
xhr: function()
{
var xhr = new window.XMLHttpRequest();
//Upload progress
xhr.upload.addEventListener
(
"progress",
function( event)
{
if( event.lengthComputable )
{
var percentComplete = Math.round( ( ( event.loaded / event.total ) * 100 ) );
// Do something with upload progress
$( '#progress' ).css( { 'width': percentComplete + '%' } );
if( percentComplete == 100 )
{
$( '#progress' ).addClass( 'finished' );
$( '#progress' ).delay( 500 ).queue
(
'fx',
function( next )
{
$( '#progress' ).addClass( 'notransition' );
$( this ).css( { width: '' } );
$( this ).removeClass( 'finished' );
next();
}
);
}
}
},
false
);
//Download progress
xhr.addEventListener
(
"progress",
function( event )
{
if( event.lengthComputable )
{
var percentComplete = Math.round( ( ( event.loaded / event.total ) * 100 ) );
// Do something with upload progress
$( '#progress' ).css( { 'width': percentComplete + '%' } );
if( percentComplete == 100 )
{
$( '#progress' ).addClass( 'finished' );
$( '#progress' ).delay( 500 ).queue
(
'fx',
function( next )
{
$( '#progress' ).addClass( 'notransition' );
$( this ).css( { width: '' } );
$( this ).removeClass( 'finished' );
next();
}
);
}
}
},
false
);
return xhr;
},
...
success: function( data, textStatus, xhr )
{
...
// Reset our ajax loading progress bar
$( '#progress' ).removeClass( 'notransition' );
...
}
Then, in your css; use this:
#progress {
position: fixed;
opacity: 1;
z-index: 2147483647;
top: 0;
left: -6px;
width: 0%;
height: 2px;
background: #b91f1f;
-moz-border-radius: 1px;
-webkit-border-radius: 1px;
border-radius: 1px;
-moz-transition: width 500ms ease-out,opacity 400ms linear;
-ms-transition: width 500ms ease-out,opacity 400ms linear;
-o-transition: width 500ms ease-out,opacity 400ms linear;
-webkit-transition: width 500ms ease-out,opacity 400ms linear;
transition: width 500ms ease-out,opacity 400ms linear;
}
#progress.finished {
opacity: 0 !important;
}
#progress.notransition {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
-ms-transition: none !important;
transition: none !important;
}
#progress dd,#progress dt {
position: absolute;
top: 0;
height: 2px;
-moz-box-shadow: #b91f1f 1px 0 6px 1px;
-ms-box-shadow: #b91f1f 1px 0 6px 1px;
-webkit-box-shadow: #b91f1f 1px 0 6px 1px;
box-shadow: #b91f1f 1px 0 6px 1px;
-moz-border-radius: 100%;
-webkit-border-radius: 100%;
border-radius: 100%;
}
#progress dd {
opacity: 1;
width: 20px;
right: 0;
clip: rect(-6px,22px,14px,10px);
}
#progress dt {
opacity: 1;
width: 180px;
right: -80px;
clip: rect(-6px,90px,14px,-6px);
}
@-moz-keyframes pulse {
30% {
opacity: 1
}
60% {
opacity: 0
}
100% {
opacity: 1
}
}
@-ms-keyframes pulse {
30% {
opacity: .6
}
60% {
opacity: 0
}
100% {
opacity: .6
}
}
@-o-keyframes pulse {
30% {
opacity: 1
}
60% {
opacity: 0
}
100% {
opacity: 1
}
}
@-webkit-keyframes pulse {
30% {
opacity: .6
}
60% {
opacity: 0
}
100% {
opacity: .6
}
}
@keyframes pulse {
30% {
opacity: 1
}
60% {
opacity: 0
}
100% {
opacity: 1
}
}
#progress.waiting dd,#progress.waiting dt {
-moz-animation: pulse 2s ease-out 0s infinite;
-ms-animation: pulse 2s ease-out 0s infinite;
-o-animation: pulse 2s ease-out 0s infinite;
-webkit-animation: pulse 2s ease-out 0s infinite;
animation: pulse 2s ease-out 0s infinite
}
#progress.notransition dd,#progress.notransition dt {
-moz-animation: none !important;
-ms-animation: none !important;
-o-animation: none !important;
-webkit-animation: none !important;
animation: none !important;
}
And now you should have a loader that works for each AJAX operation...and really works to represent the true percentage of how much of the response has been received, instead of just playing a fancy animation when you first load the main page.
To make it operational on the initial page load (i.e. its not actually displaying legitimate progress), use the method that Nathan Srivi mentions in a document.ready
function above and beyond what I already mentioned:
$( document ).ready(function() {
$({property: 0}).animate({property: 105}, {
duration: 4000,
step: function() {
var _percent = Math.round(this.property);
$('#progress').css('width', _percent+"%");
if(_percent == 105) {
$("#progress").addClass("done");
}
},
complete: function() {
alert('complete');
}
});
});
Lastly,
You will need to ensure that 'Content-Length' headers are being sent to the browser in order for a loader of this design to work correctly...otherwise the event.lengthComputable
member resolves to false...and no progress bar will load.
HTH, feel free to edit inconsistencies.