• JavaScript / JQuery Downloading a File Using POST on an Anchor Tag

    download imageWhen making a recent update to a web application, I came across a need to change the method of downloading a file from a simple click on a link (HTML <a> tag) to submitting data to the server via a POST request. The reason for needing to do this is based on the code on the server side that I was hooking into – so there really was little option when it came to how the file was fetched – it had to be via POST. The file also does not exist on the server – it is dynamically created when the link is clicked on, and I did not want to have to create a file temporarily.

    I did not want the POST event to result in the opening (and closing) of a new browser window or tab, which happens fairly frequently on websites that I have used. It was important to the front-end user that the visible link functionality remained unchanged. As a result, I started looking into the possibility of submitting the form using AJAX or JavaScript. The trouble is that due to security restrictions, JavaScript executed on browsers is not actually given permission to save files to the user’s machine. As a result, an AJAX post was out of the question.

    The approach I opted for is detailed below. I made a couple of minor changes to the HTML file, adding a JavaScript call to the link and adding an empty <form> element. I am assuming a basic knowledge of JQuery.

    Update 11th June 2013: One thing I didn’t mention when I first wrote this article was that iOS devices cannot download files traditionally. As a result of this, the approach suggested here will not work, and there needs to be a minor amendment made to JavaScript which causes the file to be downloaded in a new browser tab. If the iOS device is able to display the data, it will do and will also offer options to load the data in a different browser. The Javascript code includes an update. The same will be true for other tablet / phone devices (e.g. Android devices) so further tweaks will be necessary to perform downloads – the trouble is that ‘Android’ is not always presented as the user agent.

    <html>
        <head>
            <!-- head content -->
        </head>
        <body>
            <!-- some body HTML content -->
            <a onclick="downloadFile()" href="javascript:void(0)">Download File</a>
            <!-- more body HTML content -->
            <form target="downloadFrame" action="/actions/download/" id="form_jsSubmit" />
        </body>
    </html>

    The JavaScript function called in the link is responsible for setting up the content of the form (adding inputs to it as necessary), adding the iFrame into the DOM and finally submitting the form:

    function downloadFile() {
        // Add necessary hidden inputs to form
    
        // If the iFrame has been added before, be sure to delete it
        $("#download_iFrame").remove();
    
        // Add a new (blank) iFrame to the HTML DOM (right at the end of the body)
        $("body").append('<iframe name="downloadFrame" id="download_iFrame" style="display: none;" src="" />');
    
        // Before submitting the form, check to see whether this is an iOS/Android device, and change the method of download if it is.
        var iOS = ( navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false );
        var android = navigator.userAgent.toLowerCase().match(/android/g) ? true : false;
        if (iOS || android)
            $("#form_jsSubmit").attr("target", "_blank");
    
        // Submit the form using JavaScript
        $("#form_jsSubmit").submit();
    }

    When the form is submitted, it will return to the iFrame. The iFrame will see from the type of data being returned that it is a file, and the browser will download the file. This is a very basic solution, to which there can be multiple extensions. The first, and probably most obvious is what to do if there is an error fetching the file – the code above does not deal with that scenario – it always assumes that a file will be generated and sent for download.

One Responseso far.

  1. Lorenz Bausch says:

    The same problem exists with file uploads. Thats why most of my web applications contain an iframe “devnulliframe”.

Leave a Reply

Your email address will not be published. Required fields are marked *

Are you human: *