Introduction
There are many ways to produce PDF on a website. You can use server side solutions for creating PDF, create CSS styles for print (and cross your finger waiting that all browser vendors will implement it) or create PDF on the client side. The two last solutions having the advantage not to take too much CPU on your infrastructure.Leveraging PDFKit and SimpleSchema
PDFKit provides an almost complete isomorphic solution for that. It allows you to choose where you want to implement your PDF creation. Very nice. Unfortunately (or not), it only comes with low drawing primitives and for creating your PDF you will need some serious work on it.When creating templates and forms for our collections, most of us are relying on Autoform. This solution is so nice that we tend to forget how incredible the amount of work this solution is doing for us. We just create a SimpleSchema of our collection and now we can display them, fill them, check the integrity of data provided by our users, and so forth. An incredibly productive package suite.
What if we could do the same for our PDF? That's what I was needing for a client. A solution that could take collections and create PDF out of them.
PDF Renderer
I've outsourced this solution in a package called pierreeric:pdfrenderer. Let's see a simple example on how to use it.First, we start creating our classic collection with a SimpleSchema. We tag the fields that we want to see in our PDF using a simple pdf: true attribute:
CustomerSchema = new SimpleSchema name: type: String label: TAPi18n.__ 'name' images: type: String label: TAPi18n.__ 'images' optional: true autoform: afFieldInput: type: 'fileUpload' collection: 'Images' address: type: Object label: TAPi18n.__ 'address' 'address.street': type: String label: TAPi18n.__ 'street' pdf: true 'address.city': type: String label: TAPi18n.__ 'city' pdf: true Customers = new Mongo.Collection 'customers' Customers.attachSchema CustomerSchema if Meteor.isServer if Customers.find().count() is 0 Customers.insert name: 'Mathilde Charpentier' address: street: '227, rue Camille de Richelieu' city: 'Strasbourg' Meteor.publish 'customers', -> Customers.find() if Meteor.isClient Template.svgTest.onCreated -> sub = @subscribe 'customers' @autorun => if sub.ready() @customer = Customers.findOne() Template.svgTest.helpers customer: -> Template.instance().customerNow for creating the PDF when the user click on a button, we can pass to the PdfRenderer some fields or the complete collection:
if Meteor.isClient Template.svgTest.events 'click button': (e, t) -> # Create the initial PDF document pdf = new PdfRenderer size: 'a4' # Load all required assets pdf.addAsset "/cfs/files/images/#{t.customer.images}" if t.customer.images # Use reactivity for loading assets if any t.autorun -> if pdf.ready() # Customer image if exists if t.customer.images? pdf.img "/cfs/files/images/#{t.customer.images}", 'RIGHT', width: 100 # Customer's name pdf.h1 t.customer.name # Address of customer pdf.h2 TAPi18n.__ 'address' pdf.schema CustomerSchema, 'address', t.customer # End the PDF document, display it and enable back the PDF button pdf.finish "file-#{t.customer.name}.pdf", -> console.log 'PDF finished'You can see a rendered PDF in the Github repository.