Cameron
Cameron

Reputation: 28853

Get progress of AJAX call to get JSON in Rails

I have the following JS to retrieve some JSON data from a controller method in a Rails app:

$.ajax({
    xhr: function() {
        var xhr = $.ajaxSettings.xhr();
        xhr.onprogress = function(e) {
            if (e.lengthComputable) {
                console.log(e.loaded / e.total);
            }
        };
        xhr.upload.onprogress = function(e) {
            if (e.lengthComputable) {
                console.log(e.loaded / e.total);
            }
        };
        return xhr;
    },
    cache: false,
    url: '/get_data',
    method: 'GET',
    dataType: 'JSON',
    success: function(data) {
        console.log(data);
    }
});

And the method is as follows:

def get_data
  @data = [{....}]
  respond_to do |format|
    format.html
    format.json do
      response.headers['Content-Length'] = @data.to_s.length.to_s
      render json: @data
    end
  end
end

The method can take up to 3-4 seconds to return due to the @data being either large or requiring complex calculations first, so I want to show a progress bar whilst the AJAX is taking place.

Note: I don't just want to show a loader that shows before and after the AJAX, but actually show the progress!

However I'm finding that lengthComputable is always false...

How can I get Rails to send back the correct progress? I've added the Content-Length header but it never shows up in the response...

Upvotes: 2

Views: 1301

Answers (3)

I was wrong. It's not a real progress Bar, but the idea was this:

$(function() {
  var pg = 0;

  function progressbarAdd(){
    pg++;
    $('#bar').progressbar('option', 'value', pg).children('.ui-progressbar-value').css('display', 'block'); 
  }
  
  $('#bar').progressbar({ value: 0 });
  
  $(document).on({
    ajaxStart: function(){
      timer = setInterval(function(){ 
        progressbarAdd()
      }, 100);
    },
    ajaxStop: function(){
      clearTimeout(timer);  
      $('#bar').progressbar('option', 'value', 100);
    }    
  });
  
                
  $.ajax({
    method: 'GET',
    url:'https://viacep.com.br/ws/01001000/json/',
    dataType: 'json',
    success: function() {
      console.log('JSON:', arguments[0]);
    },
    error: function() {
      console.log('Fail');
    }
  });
});
<!DOCTYPE html>
<html>
    <head>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
        <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"></script>
        <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/black-tie/jquery-ui.css" />
    </head>
    <body>
        <div id="bar"></div>
    </body>
</html>

Upvotes: 1

Use jQuery to know when the request has finished.

$(document).on({
    ajaxStart: function(){
        //show or create the progress bar
    },
    ajaxStop: function(){
        //hide or remove the progress bar
    }    
});

Upvotes: 0

Endless
Endless

Reputation: 37975

The ProgressEvent.lengthComputable read-only property is a Boolean flag indicating if the resource concerned by the ProgressEvent has a length that can be calculated.

Meaning it needs a content-length header... to know how big the resource is. What you are probably doing is sending a application-octet stream with no know size

Upvotes: 0

Related Questions