0

I'm using Bootstrap to show a page, some of it is an extract of data. I've added a download button that brings up a modal dialog, including a date range picker, a close and download buttons to allow downloading a larger range of that data.

An extract of the Modal code:

          <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h3 class="modal-title" id="DownloadModalLabel">Download Data </h3>
      </div>
      <div class="modal-body">
        <form id="download_form" action="api-dl.php" method="get">
          <div class="form-group">
            <label for="channel-name" class="control-label">Download Period:</label>
            <input type="text" name="daterange" value="<?php echo $DownloadDateStart . " - " . $DownloadDateEnd; ?>" />
          </div>
          <div class="form-group hidden">
            <input type="text" id="channel-id" name="channel-id" class="channel-id" value="ha" />
            <input type="text" name="site-id" class="site-id" value="<?php echo $SITE; ?>" />
          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" id="submitForm" class="btn btn-primary" data-dismiss="modal">Download CSV</button>
      </div>

Further down I have a script responds to the submit button:

    $(document).ready(function () {
      $("#download_form").on("submit", function(e) {
        var postData = $(this).serializeArray();
        var formURL = $(this).attr("action");
        $.ajax({
          url: formURL,
          type: "GET",
          data: postData,
        });
      e.preventDefault();
      });
      $("#submitForm").on('click', function() {
        $("#download_form").submit();
      });
    });

You'll note that I call a php file "api-dl.php" to extract data and respond with a CSV file. Cut back to a bare minimum fake one line response that file looks like:

header('Content-Disposition: attachment; filename="12345678.csv";');
header('Content-Type: "text/csv"');
header("Content-Length: 32");
header("Cache-Control: no-cache, no-store, must-revalidate");
header("Pragma: no-cache");
header("Expires: 0");
//
echo '"15/10/2016", "12:00", "1.234\n"';

At this point I've tried lots of flushing and outputting to php output stream and the like. Always I get in the inspect pane on my browser:

Request Headers:

Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Connection:keep-alive
Cookie:PHPSESSID=.....
Host:r ....  .net.au
Referer:http://r ....  .net.au/site.php?region=Test&site=Test
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.90 Safari/537.36 Vivaldi/1.4.589.11
X-Requested-With:XMLHttpRequest

Response Headers:

Cache-Control:no-cache, no-store, must-revalidate
Connection:Keep-Alive
Content-Disposition:attachment; filename="12345678.csv";
Content-Length:32
Content-Type:"text/csv"
Date:Sat, 24 Sep 2016 00:53:13 GMT
Expires:0
Keep-Alive:timeout=5, max=100
Pragma:no-cache
Server:Apache/2.4.18 (Ubuntu)

To my mind that looks right I've tried 1,248 variations on this theme. In the "Response" tab I see the response I expect:

"15/10/2016", "12:00", "-1.234"

But for the life of me I can't make a browser download that.

I have seen some Javascript that looked nice but the data isn't available on the client side, it's in a database on the server.

I can't be missing much I think - what do you think it could be?

Scott May
  • 15
  • 4

3 Answers3

0

XHR can't handle download. Browser won't work with such solution. Please change your response in api-dl.php file, and return there only a link to download. Next, your ajax will be looking like this:

$.ajax({
    url: formURL,
    type: "GET",
    data: postData,
    success: function(response){
        window.open(response);
    }
});

After you will see how browser downloads a file.

michail_w
  • 4,318
  • 4
  • 26
  • 43
  • This will make call two calls and its mentioned as complicated. one to provide the URL and another to open it, we know the target URL. So we can directly give location.href with start and end animation. Ref : http://stackoverflow.com/questions/3346072/download-csv-file-using-ajax – Senthil Sep 24 '16 at 01:47
0

This works fine. forcing a download, you can redirect the current page to the download link. Ref: Download CSV file using "AJAX"

<script type="text/javascript">
$(document).ready(function () {
    $("#download_form").on("submit", function(e) {
        $('#wait-animation').show(); /* If required show animation */
        var postData = $(this).serializeArray();
        var site_id = $('.site-id').val();  
        var channel_id = $('.channel-id').val();            
        var daterange = $('.daterange').val();      
        document.location.href = $(this).attr("action")+"?site_id"+site_id+"&daterange="+daterange;
        /*e.preventDefault();*/
        $('#wait-animation').hide(); /* hide animation after download completes*/
  });
  $("#submitForm").on('click', function() {
    $("#download_form").submit();
  });
});
</script>
Community
  • 1
  • 1
Senthil
  • 2,156
  • 1
  • 14
  • 19
0

I almost do the same thing but try appending readfile at the end of your header strings on the php file that triggers the download. example:

<?php
$file = "http://path_to_some_file.csv;
header('Content-Type: text/csv; charset=utf-8');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename="any_name_of_file.csv");
readfile($file);
?>