I have a page that allows the user to download a dynamically-generated file. It takes a long time to generate, so I'd like to show a "waiting" indicator. The problem is, I can't figure out how to detect when the browser has received the file, so I can hide the indicator.
I'm making the request in a hidden form, which POSTs to the server, and targets a hidden iframe for its results. This is so I don't replace the entire browser window with the result. I listen for a "load" event on the iframe, in the hope that it will fire when the download is complete.
I return a "Content-Disposition: attachment" header with the file, which causes the browser to show the "Save" dialog. But the browser doesn't fire a "load" event in the iframe.
One approach I tried is using a multi-part response. So it would send an empty HTML file, as well as the attached downloadable file. For example:
Content-type: multipart/x-mixed-replace;boundary="abcde"
--abcde
Content-type: text/html
--abcde
Content-type: application/vnd.fdf
Content-Disposition: attachment; filename=foo.fdf
file-content
--abcde
This works in Firefox; it receives the empty HTML file, fires the "load" event, then shows the "Save" dialog for the downloadable file. But it fails on IE and Safari; IE fires the "load" event but doesn't download the file, and Safari downloads the file (with the wrong name and content-type), and doesn't fire the "load" event.
A different approach might be to make a call to start the file creation, then poll the server until it's ready, then download the already-created file. But I'd rather avoid creating temporary files on the server.
Does anyone have a better idea?
old thread, i know...
but those, that are lead here by google might be interested in my solution. it is very simple, yet reliable. and it makes it possible to display real progress messages (and can be easily plugged in to existing processes):
the script that processes (my problem was: retrieving files via http and deliver them as zip) writes the status to the session.
the status is polled and displayed every second. thats all (ok, its not. you have to take care of a lot of details [eg concurrent downloads], but its a good place to start ;-)).
the downloadpage:
getstatus.php
download.php
When the user triggers the generation of the file, you could simply assign a unique ID to that "download", and send the user to a page which refreshes (or checks with AJAX) every few seconds. Once the file is finished, save it under that same unique ID and...
Then you can skip the whole iframe/waiting/browserwindow mess, yet have a really elegant solution.
A quick solution if you only want to display a message or a loader gif until the download dialog is displayed is to put the message in a hidden container and when you click on the button that generate the file to be downloaded you make the container visible. Then use jquery or javascript to catch the focusout event of the button to hide the container that contain the message
A very simple (and lame) one line solution is to use the
window.onblur()
event to close the loading dialog. Of course, if it takes too long and the user decides to do something else (like reading emails) the loading dialog will close.I wrote a simple JavaScript class that implements a technique similar to the one described in bulltorious answer. I hope it can be useful to someone here. The GitHub project is called response-monitor.js
By default it uses spin.js as the waiting indicator but it also provides a set of callbacks for implementation of a custom indicator.
JQuery is supported but not required.
Notable features
Example usage
HTML
Client (plain JavaScript)
Client (JQuery)
Client with callbacks (JQuery)
Server (PHP)
For more examples check the examples folder on the repository.
i use the following to download blobs and revoke the object-url after the download. it works in chrome and firefox!
after the file download dialog is closed, the window gets her focus back so the focus event is triggered.