33

I have a basic page with a navigation bar on top, and a wrapper body.

Whenever a user clicks on a navigation link it uses .load to load the page content into the wrapper div.

$(this).ajaxStart(function(){$('.progressbar .bar').css('width','5%');$('.progressbar').fadeIn();});
$(this).ajaxEnd(function(){$('progressbar').hide();});

$('.ajaxspl').on('click',function(e){
    e.preventDefault();

    var url=$(this).data('url'),
        wrap=$('body #wrap');

    //clean the wrapper
    wrap.slideUp().html('');

    //load page into wrapper
    wrap.load(url,function(){wrap.slideDown();});
});

Example of return value from .load:

<div>
...content
</div>
<script>$('.progressbar .bar').css('width','30%');</script>
<link href="/assets/css/datepicker.css" rel="stylesheet" />
<script>$('.progressbar .bar').css('width','60%');</script>
<link href="/assets/css/main.css" rel="stylesheet" />
<script>$('.progressbar .bar').css('width','90%');</script>
<script>//blah blah</script>

As you can see, I have a Bootstrap progress bar that I show on ajaxstart(), and on the page that I call I modify that value of the progress bar after each item is loaded.

This works nicely on Firefox and I can see the progress bar while waiting for the page to load, but it does not work on Chrome or IE.

Is there a better way to do this? Am I doing this correctly or is there another method to do this?

For example, getting $.ajax page size in kb and update progress bar on the fly as data is received?

I am trying to produce something similar to the Loading page when Gmail is loading.

adamdehaven
  • 5,890
  • 10
  • 61
  • 84
Zalaboza
  • 8,899
  • 16
  • 77
  • 142

2 Answers2

75

Allow me to refer you to this page , it desribes how you can add a progress event listener to the xhr object (which only works in these browsers, in older browsers you simply have rely on the same base you're currently using) in jquery.

For reference I have copied the relevant code below (you would only be interested in the 'Download progress' part probably):

$.ajax({
  xhr: function()
  {
    var xhr = new window.XMLHttpRequest();
    //Upload progress
    xhr.upload.addEventListener("progress", function(evt){
      if (evt.lengthComputable) {
        var percentComplete = evt.loaded / evt.total;
        //Do something with upload progress
        console.log(percentComplete);
      }
    }, false);
    //Download progress
    xhr.addEventListener("progress", function(evt){
      if (evt.lengthComputable) {
        var percentComplete = evt.loaded / evt.total;
        //Do something with download progress
        console.log(percentComplete);
      }
    }, false);
    return xhr;
  },
  type: 'POST',
  url: "/",
  data: {},
  success: function(data){
    //Do something success-ish
  }
});

Do allow me to say though that this is a lot of overkill for a single page website and only really becomes useful for large files. Additionally images and similar media aren't handled in this way and you would need to monitor the loading of images (or do it yourself through ajax) to make such a system perfect.

Here is a JSFiddle showing this in action: http://jsfiddle.net/vg389mnv/1/

David Mulder
  • 26,123
  • 9
  • 51
  • 114
  • 2
    I found [this library](https://github.com/rstacruz/nprogress) very useful for my requirement. Its awesome. – RN Kushwaha Oct 30 '15 at 15:27
  • @RNKushwaha Honestly, don't jump to conclusions in that case ;-) Instead ask for help if you can't get an answer to work. I assumed in good faith that this answer was outdated and thus nearly ended up deleting it. Oh well, apologies for my pretty harsh comment before and glad you got your project working :) . – David Mulder Oct 30 '15 at 19:05
  • Please note that; it is working only with `asynch: true` – fozuse Nov 07 '15 at 12:25
  • @JustMichael: Second line: 'which only works in these browsers', where 'these browsers' is a link ;-) So the answer is no. – David Mulder Nov 12 '15 at 16:32
  • @DavidMulder Not a complete "no", it works in IE10 ... :) – Asons Jan 03 '16 at 19:51
  • @JustMichael You can check browser support here http://caniuse.com/#search=XMLHttpRequest – Ikhlak S. Jan 05 '16 at 10:13
  • @witoong623 And `lengthComputable` is `true`? Because that shouldn't happen. – David Mulder May 05 '16 at 08:05
  • @DavidMulder Yes, it is. I'm sorry, I didn't look into it before comment, but why it's uncomputable? I use GET method to get array of object and It'll become computable when response return empty array. – witoong623 May 05 '16 at 09:24
  • @witoong623 The response is probably missing a `Content-Length` header. – David Mulder May 05 '16 at 09:34
11

The above answer is correct (upvoted). A custom xhr request works well, I tested it with your code (and a bigger file to see actual progress), might as well copy it here:

$('.ajaxspl').on('click',function(e){
    e.preventDefault();

    var url=$(this).data('url'), wrap=$('body #wrap');

    //clean the wrapper
    wrap.slideUp().html('');

    //load page into wrapper
    console.log('starting ajax request');
    $.ajax({
        xhr: function() {
            var xhr = new window.XMLHttpRequest();
            xhr.addEventListener('progress', function(e) {
                if (e.lengthComputable) {
                    $('.progressbar .bar').css('width', '' + (100 * e.loaded / e.total) + '%');
                }
            });
            return xhr;
        }, 
        type: 'POST', 
        url: url, 
        data: {}, 
        complete: function(response, status, xhr) {
            console.log(response)
            wrap.html(response.responseText);
            wrap.slideDown();
        }
    });

});
Laszlo R.
  • 126
  • 3