Open a "Save As" / "Download" dialog with JavaScript to download a file created on the fly

14,053

Is it possible?

Of course. Let's have an example:

  1. The app shows a table to the user

You mean, something along the lines of using a <table> tag:

<table>
    <tr>
        <td>Foo bar</td>
        <td>123</td>
        <td>
            <form action="/download/foo/bar/123" method="post">
                <button type="submit" value="Download foo bar 123" />
            </form>
        </td>
    </tr>

    ... here come some other rows of the table ...
</table>
  1. The user push the download button

OK, this one is obvious. The user submits the form by clicking on the corresponding submit button on the desired row of your table.

  1. JavaScript sends data to a server side endpoint

Why care about javascript when you have standard HTML forms which can submit data to the server in a purely browser agnostic manner, like shown in point 1.? And if you really cared about some javascript you could always subscribe to the onsubmit action of the <form> I showed earlier and inject the necessary data as hidden fields into the DOM using javascript.

  1. The server generate the file on the fly based on the data sent from the client

Yeah, that's like standard HTTP protocol. The server will simply handle the /download/foo/bar/123 endpoint and simply send the file as attachment:

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 29
Content-Disposition: attachment; filename=foobar123.bin

HERE COMES THE BINARY CONTENT
  1. The browser open the download/save as dialog

That's exactly what any browser's gonna do when it handles the previously shown HTTP response from a server.

Conclusion: The HTTP protocol and standard HTML forms already provide you with the necessary tools to achieve your requirements. And if you wanted a little bit of additional fanciness, just enhance the HTML form upon submission using javascript in order to append any required fields as hidden input elements that you would like to send to the server. And then leave it to the browser to handle the download.

Share:
14,053
raben
Author by

raben

Updated on June 05, 2022

Comments

  • raben
    raben almost 2 years

    I have a NGINX+Flask+KnockoutJS single page app and I want to create a download button that allow the user to download the data he/she is visualising and manipulating client side without reloading the full page There are a number of pure JavaScript solutions (like download.js) but none of them is fully compatible with all major browsers (e.g. Safari).

    Basically what I would like to have is:

    1. The app shows a table to the user
    2. The user push the download button
    3. JavaScript sends data to a server side endpoint
    4. The server generate the file on the fly based on the data sent from the client
    5. The browser open the download/save as dialog

    Is it possible?

  • dandavis
    dandavis about 8 years
    safari doesn't support a[download], as per OP... caniuse.com/#feat=download
  • Scott Marcus
    Scott Marcus about 8 years
    Doesn't really change the fact of my answer, which is the the browser dictates what to do with downloaded files, not any JS code.
  • raben
    raben about 8 years
    @ScottMarcus you are right, but the point is not the dialog per se. I just used this to explain the fact that I want the file to be downloaded and not opened in the browser.
  • raben
    raben about 8 years
    Thank you, I do care about JavaScript because I want do download the file without a page refresh (I edited my question to clarify) I tried to send a POST HTTP request to my server app endpoint but even if the HTTP response is successful the file is not downloaded.
  • Darin Dimitrov
    Darin Dimitrov about 8 years
    There's no page refresh if the user POSTs an HTML form to a server side endpoint which streams a file with a Content-Disposition: attachment header as shown in my answer. A Save As dialog is simply shown for the user to select the file destination and no page reload occurs whatsoever.
  • raben
    raben about 8 years
    Oh, I didn't know it! I will try it.