I have a link that the user clicks to get a PDF. In jQuery, I create a POST ajax call to the server to get the PDF. The PDF comes to me with the correct content headers et
The jQuery Plugin for Requesting Ajax-like File Downloads is - essentially - creating a form, adding the post data as hidden field(s), adding it to the body of the page, submitting it and removing it.
In my case I did not have a form, only a chunk of data to be posted as it was. That made for the following solution. On the server side I can get the data by simply reading the "data" parameter from the request and URI-decoding it.
function postAndDownload(url, data) {
encodedData = encodeURIComponent(data);
$("<form>")
.attr("action", url)
.attr("method", "post")
.append(
$("input")
.attr("type", "hidden")
.attr("name", "data")
.attr("value", encodedData)
)
.appendTo("body")
.submit()
.remove();
};
I think the best will be to create a temp pdf file in the downloads folder and then load the file using pop-up having an iframe.. chrome will load it instantly but I suppose for other variants Acrobat reader must be installed to view the pdf but again you can use FlashPaper too :)
Take a look at - jQuery Plugin for Requesting Ajax-like File Downloads
The whole plugin
is just about 30 lines of code (including comments).
The call is fairly similar to jquery ajax call.
$.download('/export.php','filename=myPDF&format=pdf&content=' + pdfData );
Ofcourse, you have to set the content-type and Content-Disposition headers on the server side as you would for any such download.
In java I would do something like this
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename="exported.pdf");
You don't need jQuery at all. Just submit your POST via a form normally, and on the server side, add the HTTP header
Content-Disposition: attachment; filename="whatever.pdf"
The browser will do its default thing.
Alternately, if you want to be more careful about reporting any errors that might occur during the PDF generation, you can do this. POST your parameters to your server with jQuery. On the server, generate the binary content and cache it somewhere for a few minutes, accessible via a key that you put in the user's session, and return a "success" Ajax response to your page (or if there was an error, return an "error" response). If the page gets back a success response, it can immediately do something like:
window.location = "/get/my/pdf";
The server then returns the cached PDF content. Be sure to include the Content-Disposition header, as above.
I had the same problem but on top use an RESTFUL webservice
for this and have an complex data object which i must post.
My solution:
like the jQuery Plugin i build a temp formular and submit it. But i send the data object as an parameter with json content (i use here AngularJS
but it should work with jQuery.param()
too.)
Javascript:
$('<form target="_blank" action="' + appConstants.restbaseurl + '/print/pdf" method="POST">' +
"<input name='data' value='" + angular.toJson($scope.versicherung) + "' />" +
'</form>').appendTo('body').submit().remove();
on the server side we use a CXF REST Service
with an JACKSON
Provider:
Spring Config:
<jaxrs:server id="masterdataService" address="/">
<jaxrs:serviceBeans>
<ref bean="printRestServiceBean" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
<bean class="de.controller.ExceptionHandler" />
</jaxrs:providers>
</jaxrs:server>
in the controller i extracted the param and converted it back to an Java Pojo:
package de.controller;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
@Path(Constants.PRINT_PATH)
@Consumes({ MediaType.APPLICATION_JSON, "application/x-www-form-urlencoded"})
@Produces("application/pdf; charset=UTF-8")
public class PrintRestController {
@Autowired
private PrintService printService;
@POST
@Produces("application/pdf")
@Path("/pdf")
public Response getPDF(@FormParam("data") String data) {
return printService.getPDF(json2Versicherung(data));
}
private Versicherung json2Versicherung(String data) {
Versicherung lVersicherung = null;
try {
ObjectMapper mapper = new ObjectMapper();
lVersicherung = mapper.readValue(data, Versicherung.class);
} catch(Exception e) {
LOGGER.error("PrintRestController.json2Versicherung() error", e);
}
return lVersicherung;
}
}
in the PrintService i build the pdf binary and the response:
@Override
public Response getPDF(Versicherung pVersicherung) {
byte[] result = ... //build the pdf from what ever
ResponseBuilder response = Response.ok((Object) result);
response.header("Content-Disposition", "inline; filename=mypdf.pdf");
return response.build();
}
This solution works for all browsers (even for IE9 which can't handle data url's) and on tablets and smartphone and it have no problems with popupblockers
I fail to understand why you want an ajax request to a file download url! But if it's more like client itself generates some content for download - use a data uri. Works perfectly for Chrome and Firefox 20+. Safari and IE NOT! If Flash is allowed, you could use downloadifier.
Ah after reading your code, I see you want to send a bunch of parameters. Well unless the query string gets too long (IE8- has a limit of 2083) why not simply use an anchor with proper url?
$('a.export-csv').click( function (evt){
linkEl.attr('href','/export?' + encodeURIComponent(formQueryString()));
return true;
});
The above allows you to change the URL before the default event (the click) happens.