I have a javascript app that sends ajax POST requests to a certain URL. Response might be a JSON string or it might be a file (as an attachment). I can easily detect Content-Type and Content-Disposition in my ajax call, but once I detect that the response contains a file, how do I offer the client to download it? I've read a number of similar threads here but none of them provide the answer I'm looking for.
Please, please, please do not post answers suggesting that I shouldn't use ajax for this or that I should redirect the browser, because none of this is an option. Using a plain HTML form is also not an option. What I do need is to show a download dialog to the client. Can this be done and how?
EDIT:
Apparently, this cannot be done, but there is a simple workaround, as suggested by the accepted answer. For anyone who comes across this issue in the future, here's how I solved it:
$.ajax({
type: "POST",
url: url,
data: params,
success: function(response, status, request) {
var disp = request.getResponseHeader('Content-Disposition');
if (disp && disp.search('attachment') != -1) {
var form = $('<form method="POST" action="' + url + '">');
$.each(params, function(k, v) {
form.append($('<input type="hidden" name="' + k +
'" value="' + v + '">'));
});
$('body').append(form);
form.submit();
}
}
});
So basically, just generate a HTML form with the same params that were used in AJAX request and submit it.
I used this FileSaver.js. In my case with csv files, i did this (in coffescript):
I think for most complicated case, the data must be processed properly. Under the hood FileSaver.js implement the same approach of the answer of Jonathan Amend.
For those looking for a solution from an Angular perspective, this worked for me:
Here is my solution using a temporary hidden form.
Note that I massively use JQuery but you can do the same with native JS.
see: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ it'll return a blob as a response, which can then be put into filesaver
What server-side language are you using? In my app I can easily download a file from an AJAX call by setting the correct headers in PHP's response:
Setting headers server-side
This will in fact 'redirect' the browser to this download page, but as @ahren alread said in his comment, it won't navigate away from the current page.
It's all about setting the correct headers so I'm sure you'll find a suitable solution for the server-side language you're using if it's not PHP.
Handling the response client side
Assuming you already know how to make an AJAX call, on the client side you execute an AJAX request to the server. The server then generates a link from where this file can be downloaded, e.g. the 'forward' URL where you want to point to. For example, the server responds with:
When processing the response, you inject an
iframe
in your body and set theiframe
's SRC to the URL you just received like this (using jQuery for the ease of this example):If you've set the correct headers as shown above, the iframe will force a download dialog without navigating the browser away from the current page.
Note
Extra addition in relation to your question; I think it's best to always return JSON when requesting stuff with AJAX technology. After you've received the JSON response, you can then decide client-side what to do with it. Maybe, for example, later on you want the user to click a download link to the URL instead of forcing the download directly, in your current setup you would have to update both client and server-side to do so.
Create a form, use the POST method, submit the form - there's no need for an iframe. When the server page responds to the request, write a response header for the mime type of the file, and it will present a download dialog - I've done this a number of times.
You want content-type of application/download - just search for how to provide a download for whatever language you're using.