Handlebars to PDF Component

I have extended @jmikem's PDF component which is based on @church's tutorial on html2pdf and added handlebars.js to the mix.

You pass in a handlebars template, some css and some JSON and you will get back a PDF ready to download.

This is the component JSON file and here is a sample app that uses it to make an invoice.

A few notes.

  • This uses jsPDF and not html2pdf. I could never get pagination working with html2pdf. jsPDF has pretty rudimentary pagination (it will only prevent page breaks within text), but hey, at least that much actually works!
  • This might be a little rough around the edges, buyer beware!
  • Since both Retool and Handlebars.js use curly braces {{ }} this causes a conflict. So your Handlebars templates will use double square brackets instead [[ ]] and the component translates these for use by Handlebars.
  • You cannot use image URLs in your templates. There are CORS issues with this that I don't think are avoidable (I spent many hours trying!). So you need to convert your images to base64 and use those. My sample app shows how to pass an image in the JSON data using base64. Here is a site that will do the conversions: https://www.base64-image.de/
  • This is hard coded for A4 in portrait and px units. jsPDF get a little squirrely when going to inch units so I kept it metric-ish which seems to work (I did say it was a little rough around the edges didn't I?)
  • Handlebars.js documentation can be found here.
  • I included a couple of helpers. currency converts a numeric value into US dollars (sorry Europe!). sumTotal sums an array with a total property and returns it in dollars. sumQuantity sums an array with a quantity property. You can see how these work in the sample app.
  • The module consists of three components:
    • A PDF Viewer that does nothing but display the base64 passed to it.
    • A custom component that does all of the magic. Study this to see how things work, change margins, page orientation, modify handlebars helpers and such.
    • A Refresh button. This is needed because if you change the JSON or template the PDF will not be automatically redrawn.

Improvements that someone could work on if they so desired:

  • Direct printing without download.
  • Add Inputs for page orientation, page size, margins, canvas scaling and such things.
  • A way to pass in Handlbars helpers (not sure if this is possible but would make it more easily extensible)
  • Explore possibly using pdfMake instead of jsPDF. pdfMake talks a good game, but it is v0.2 and I ran out of steam to see if it is a better alternative to html2pdf and jsPdf.
6 Likes

Hey @bradlymathews

Incredible work!

Btw, image url works out of the box (tried with https://source.unsplash.com/400x400), I think it depends of your server' CORS header setting.

Keep it up!
Fabio

Hmm... Both my S3 and Azure storage claim to be set up for CORS and neither works for me. Apparently I did not sacrifice the right animal to the CORS Gods. :goat: :cow2: :chicken: :bison: :ram: ?

3 Likes

@bradlymathews Seriously amazing work! Something like this really should be available out of the box by Retool.

One thing I changed was removing the top bar of the pdf component and manually creating a download button so that I could manipulate the pdf name. If anyone has found a better way to do this, let me know!

The download pdf syntax looks like this if anyone is interested.

utils.downloadFile({base64Binary: customHTMLPDF.model.pdf_blob}, pdfTitle.value, 'pdf');

any way to make pdf multi page ? common google solution (

) is not working for me. thanks

It should automatically split into multiple pages.

The jsPDF docs can tell you more about its pagination capability, which is pretty rudimentary. Other libraries claim to have better pagination, but it never actually works for me.

yes you are correct , it is adding page break on it's own but that's the issue I want to break after my content is finish.

tried :

.page-break { page-break-after: always; }

Didn't work,

looking: ( html - Documentation )

hey @bradlymathews thanks so much for building this and sharing it with the community!

I was wondering if there is any way to add hyperlinks into the generated PDF?

Welcome to the forums @jolow ,

I have not tried that with jsPDF, but with all other libraries I have used you just add a standard tag and the link happens. You can also add your handlebars within the tag so the link and label can be dynamic.

Thanks for the welcome!

I've tried using an tag with a href and unfortunately it doesn't seem to be working. The generated PDF is underlined/blue i.e. looks like a hyperlink, but it is not clickable nor does it contain info about the link.

If anyone manages to figure this out do share it over here!

hi @bradlymathews this is the only way to use jspdf in retool? i cant use it like external library? how i can install those files you sent in post? i need two json?

thank you

That is the only way I know of to use jsPDF in Retool. You may be able to do all of this within a JS query, using jsPDF as an external library, but that has not yet been publicly tried for any of the PDF libraries. Feel free to try it and let us know!

You do not need to install the files, they are just referenced from an external source within the Custom Component.

I have not looked at the component in a while so I am not sure which two JSON's you are referring to, but I made this an minimal as I could, so it needs everything that is there.

1 Like

Ahh.

You only need the component JSON to add it to your own app. If you want to see it in action on my sample app, you will need both.

1 Like

which i need to download?

i see several json files, hope retool can have a free option and easier to integrate jspdf :frowning: the services like carbone documint are expensive (i need it without watermark)

That link changed on me! I swear it worked before.

I edited the original post with the correct link. If you could do me a favor and edit your post to remove the bad link which was copied, that would be appreciated.

1 Like

done

Is there a way to pass my container with existing content into this PDF exporter?

Not currently, it only takes handlebars.js seasoned HTML and a JSON data source as it's inputs.

Someone could build something like a table generator so that you could pass it a table component reference and it could build a PDF from that.

1 Like

i believe what you've suggested is the solution i have been trying to accomplish, but would you be willing to share some screenshots to get started for us super-newbies?

i appreciate all your help in this community, @bradlymathews, i've seen a lot of your posts and am learning a ton