AJAX to PDF Java howto – Mea Cup O' Jo
Skip to content


AJAX to PDF Java howto

The goal

I have a web page that generates a report. The report is displayed in the modal pop-up DIV and I need to give user option to generate PDF version of the pop-up. App is heavily AJAXed and is using JSF/facelets on the background and lots of JQuery on the client. Matter of fact – the content of pop-up is not produced directly by the server but rather preview is generated, then user selects which rows in report table she needs and only then the pop-up is populated using partially filtered markup from the preview report. So, now you can forget what I just said and remember only that I want to generate PDF out of some HTML code on my page.

Design

  • Capture HTML snippet and send it to the server
  • Make valid XHTML out of HTML snippet
  • Provide valid CSS
  • Convert HTML/CSS to XSL-FO
  • Generate PDF
  • Prompt user to save generated PDF

As a side note – this method is best suitable for relatively small content – no more than few screens

Components

  • JQuery (client)
  • css2xslfo
  • Apache FOP

Process

Capture HTML

This is done in your JavaScript on the client. In my case right in the report.xhtml page code.

$(document).ready(function(){
    $('button#pdf').click(function(){
        report.generatePdf({
            trigger: $(this),
            content : $('#genReportContent').html(),
            css : ['/myapp/css/pdfExport.css']});
    });
});

As you can see I’m passing innerHTML of element (DIV) with ID=genReportContent. I found it important to pass not the element itself since I need to do some further modifications to the submitted markup and I don’t want anything to change on the page as a result. This is a pretty typical JQuery syntax.
Also note that I’m passing in the button that triggered the event and location(s) of the external CSS files I want to use to format the HTML snippet. Now – you can choose to pass actual CSS files that are used to format the content on the originating page but I found out that having a dedicated stylesheet is probably a better idea.

Now to the actual generatePdf method:

	/**
	 * Calls PdfServlet and passes generated report for PDF conversion
	 */
	generatePdf : function(options) {
		var wrapper = $('
'); var div = $('
').html(options.content); wrapper.append(div); // remove any non-visible elements wrapper.find('.removeInReport').remove(); wrapper.find('#footerCell').attr('colspan', '6'); var content = escape(wrapper.html()); // generate form and submit since ajax will not load binary var form = $('
'); var contentParam = $(' ').val(content); var cssParam = $(' ').val(options.css); form.append(contentParam).append(cssParam); $('#reportHead').append(form); form.submit(); }

Here, I’m twice wrapping HTML that was passed in to provide the outer shell (since I’m getting internal HTML) and then removing the hidden DIVs I may have. The interesting part is – submitting pre-generated markup and CSS location(s) to the server.
Do not attempt to use AJAX call to do it! The reason for that is – you are generating binary content and unfortunately, even after setting content-type to PDF, and getting valid response- your browser will not attempt to save the generated PDF. Instead I am generating form on the fly and submitting it with 2 parameters (hidden fields) – for the content and CSS location(s). Don’t forget to escape the content (ln. 85)

Part 2 – process server request

Posted in Web stuff.


One Response

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. bjp says

    Ok, I am missing something, or I am doing it wrong. There seems to be holes either in the example or in my head. Can I download the whole thing?



Some HTML is OK

or, reply to this post via trackback.