4

When I have a form that I know will take a while to submit, I like to show a loading indicator on the submit event, so it shows up, and then gets cleared when the new page loads, something simple like this

$('#theForm').submit(function () {
    $('#loaderContainer').html('<img src="loader.gif" id="loadingGIF" />');
});

The issue I'm having is I am trying to do this for a form that does not navigate away from the page when you submit it, it is just serving up a file. I am rendering a csv in php, and serving it up. It takes anywhere from a few seconds to a minute to do it. When this happens, you never leave the page, so nothing can trigger the loader to go away. I thought I could submit to an iframe, and then kill the loader with the iframe's onLoad event:

<form action="/makeCSV" method="POST" target="iframe">


<iframe id="iframe" name="iframe"></iframe>

$("#iframe").load(function () {
    $("#loadingGIF").remove();
});

But I guess since it is just serving up a file and not loading a page, the onload event does not trigger.

If I have a form that is serving up a file, rather than navigating to a new page, is there any way to detect that the file has been served up?

If it helps, csv rendering code is below:

    <?php
    //do some stuff to generate a csv...
    $csv="heading1, heading2, heading3, heading4 \r\n";
    $csv.="value1, value2, value3, value4 \r\n";
    $csv.="a,b,c,d \r\n";
    //...
    header('Pragma: public');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Cache-Control: private', false);
    header('Content-Type: text/csv');
    header("Content-Disposition: attachment;filename=\"file.csv\"");
    echo $csv;
    exit;
    ?>
Jay Blanchard
  • 34,243
  • 16
  • 77
  • 119
chiliNUT
  • 18,989
  • 14
  • 66
  • 106
  • 1
    [See this old question I asked](http://stackoverflow.com/questions/2064882/what-are-techniques-to-get-around-the-ie-file-download-security-rules). The trick with the cookie works great. – Pointy Aug 07 '15 at 14:06
  • @Pointy The cookie trick looks great! Excellent idea. I had thought about polling for...something but I didn't know what. That's perfect. – chiliNUT Aug 07 '15 at 14:18
  • @chiliNUT I've been using it basically since Mr. Crowder provided that answer, and I've never had a problem with it. I usually have the JavaScript code make up a random number and post that with the form, and then the server-side code sends back the cookie with that random number as the value. That avoids potential problems with old cookies getting stuck. Because cookies come in the header of the response, it's usually the case that your "Loading ..." thing will go away before the browser's file handling dialog pops up (though that's not super important). – Pointy Aug 07 '15 at 14:29
  • @Pointy, working beautifully – chiliNUT Aug 07 '15 at 14:56

3 Answers3

0

I would go with a 2 step process - submit the form via ajax, build the csv, save as a temp file and return an identifier. Then set the iframe to request the file, and in the handler foir that request, serve then delete the file:

$('#form').submit(function(ev){
    ev.preventDefault();
    $('#loaderContainer').html('<img src="loader.gif" id="loadingGIF" />');
    $.post('createfile.php', $(this).serialize(), function(resp){
         var identifier = resp.intentifier;
         $('iframe').attr('src', 'servefile.php?i='+identifier);
         $('#loaderContainer').html('<!-- -->');
    }
}
//createfile.php
//create csv then
$identifier = uuid();
file_put_contents('somedir/'. $identifier .'.tmp', $csv);

echo json_encode(['indentifier'=>$identifier]);
//servefile.php
$identifier = $_GET['identifier'];
$file = 'somedir/' .$identifier .'.tmp'
//output correct headers here
readfile($file);
unlink($file);
Steve
  • 20,703
  • 5
  • 41
  • 67
0

Since you are already using JQuery, I suggest you use something that already has solved the issue in a compact/reliable way. I suggest giving jQuery File Download a try.

This answer led me to it. This may do exactly what you need and it is just a plugin that you can drop on your project and test :) Good luck.

Community
  • 1
  • 1
Katsuke
  • 590
  • 4
  • 21
0

You can check on window losing focus... pretty basic, but works for my need.

$([window, top.window]).blur(function() {
    $('BUTTON.btnLoading').removeClass('btnLoading');
});
Martin Zvarík
  • 2,120
  • 22
  • 27