Monday, February 14, 2022

Easy PDF reports in Oracle APEX

 A frequent question on APEX forums is: how do I create simple reports, like tickets, invoices etc.

Of course you can use some real report generator, like Apex Office Print (AOP) or Jasper. But in some cases the solution may be really simple: an APEX region and jsPDF to create a PDF document of that region. This may work if you are sure that your report will be just one page, like most invoices for instance.

This example was built in the sample database application, on the DEMO_ORDERS table. You can create a simple invoice page, part of which is shown here.

Invoice page


This is just a master-detail page based on  DEMO_ORDERS and  DEMO_ORDER_ITEMS and some additional CSS.
Make sure that everything you want to print is in one container region with a static id, and addressee, company info, items etc. as sub-regions of this container.

Now comes the tricky part: use jsPDF to create a PDF of the container region. I say tricky, because I found it hard to find examples using the latest jsPDF version. Most examples I found were using older versions, and apparently quite a lot has changed.

Start with attaching two JavaScript libraries to your page. jsPDF needs html2canvas to work.
I attached both libraries from a CDN:

https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js
https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js

The PRINT button on your page has a JavaScript DA.


window.jsPDF = window.jspdf.jsPDF;
var doc = new jsPDF();   
doc.html(document.getElementById('container'), {
   callback: function (doc) {
     doc.save();
   },
    width: 170,
    windowWidth:700,
    margin: [200020]
});

It took me quite some time that you need "window.jsPDF = window.jspdf.jsPDF;" on the first line. This was not really mentioned anywhere.

It was also surprising that in "margin: [200020]" the last number is the left margin, but it is actually mentioned in the documentation:

html - Documentation (githack.com)

The final result is a PDF document:


You have to trust me here that the first screenshot is of an APEX page and the second of a PDF  document.

There are some hickups in the PDF, e.g. in the email address as you can see. I haven't been using jsPDF and html2canvas long enough to know if that can be improved.  


Edit: if you face this spacing issue, try this:

Add css to the page:

body {
  letter-spacing: 0.2px;
}

Change the JavaScript code to:

window.jsPDF = window.jspdf.jsPDF;
var doc = new jsPDF ();
doc.html(document.getElementById('container'), {
   callback: function (doc) {
     doc.save();
   },
    width: 170,
    windowWidth:700,
    margin: [200020],
    html2canvas: {
      scale: .238
    }    
});

The result of these changes is: