Having a user download a file through a web page is a fairly common task, which begins with the painful task of finding out the appropriate headers. As if figuring out headers isn’t enough, what happens when you need conditional data to determine the download? The type of data that cannot be placed in the URL. Well, I naturally thought that Ajax could help send the data, and so my path down the wrong trail began.
Given a URL of http://website.com/file/
, we want to be able to POST data to the URL so that a download begins without the user leaving the page they are viewing. The reason the URL alone isn’t enough is because the data that gets downloaded is conditional based on the actions the user has taken so far. So we’ll start with a typical Ajax request.
var myAjax = new Ajax.Request(
'/file/',
{
method: 'post',
parameters: 'download=top10',
onComplete: function(r) {
// file starts downloading?
}
});
It should have been obvious before I even wrote the code, but the code above causes absolutely nothing to happen. Sure, all of the proper headers are returned by the request, but all we are left with is a JavaScript variable containing data. And there is no way to force this variable as a download on the user.
A quick Google search for Ajax File Download didn’t help the cause. This path will lead down many branches, of which the primary one suggests using a hidden iframe to force the download. Hours later I was able to force a static file to download, but never one where I tried to dynamically alter the contents of the iframe.
At this point, it was about to be “quit and do something else” time, but then the solution found me. As I was closing up the project, I saw a form tag in the file that was open. Just a simple form tag. So I created a form, threw in some hidden fields for conditional data, and submitted it:
<form id="super_form" method="post" action="/file/">
<input type="hidden" id="download" name="download" />
</form>$('download').value = 'top10';
$('super_form').submit();
Amazingly, a download file prompt appeared. And then I felt a bit stupid. In this case, no trickery was needed — just some straightforward HTML and JavaScript. Hopefully, this will save someone else some frustration down the road.
umm, why don’t you just rewrite the url according to conditions instead of doing a form submit?
If the conditions are detailed, they can get quite long. And since the max URL length for IE is ~2000, there are some situations where a POST is needed. In my case, the users are allowed to supply an infinite amount of conditions when “building” their file.
Thanks for the easy and clearly described post. Im going to try it right away
So what happened when you let the user submit a POST form, which returns nothing, and redirected to the download? What does the browser do?
If you get a 404 or some other error, the user will leave the page. A way around that is to set the target of the form to a new window.
If your download doesn’t exist, is it not better that the user see the 404 rather than having a form that silently fails to do anything?
Erg. I just re-read your second code block. It is just a regular form except it uses Javascript to set variables that would/should be set using form elements. I thought you were doing something with AJAX to get the download.
Yeah, you were pretty silly. It’s also fairly common to think that way. It comes about because you’re thinking AJAX is “doing something without updating the screen”, but AJAX is not that. AJAX is “get the server to give me a response as Javascript and execute it”.
You didn’t want Javascript, you wanted a file as a response.
You need to adjust your thinking to be more precise! :-)
By the way, here’s your hug: [[hug]].
Well, could’t you achieve the same effect with just plain HTML and no Javascript at all? Why do you need the Javascript in this example?
The conditions for the file are dynamic, so the hidden variable is always changing. I guess a similar example would be those JavaScript libraries that let you build in which functionality you would like before downloading.
We try to use ajax file uploads, but now we write plugins for browsers. Why? I think, (first) ajax upload now is not an transparent technology and (second) we have requirements for restore upload process after crash. ps: we try to use flash uploaders, but it seems also non-stable and raw…