How to Print a PDF?

I am using Carbone to generate a PDF. I usually do not need to save it (though I have that working) but just print it.

I can display the PDF just fine, but I see no way to print it from the PDF Viewer. I was playing with the iFrame but didn’t get it working there and also saw no way to print so did not pursue.

I tried to throw some html to a new tab but window.open() doesn’t work in the sandbox.

I know I could run the whole PDF gen outside of Retool but would rather not add another moving part.

2 Likes

Ok, got it figure out. The key was a custom component with Allow popups to escape sandbox enabled. Took a little bit of figuring as I am not a React guy, but luckily I have done a bit with vue.js. The other thing that got me a head start was this post from @church.

Here is how I did this with Carbone.io for other to follow.

Set up an account with carbone.io and make a template. I will let their docs guide you in this.

Drop a custom component on the app.

Turn on Allow popups to escape sandbox.

Edit the model to pass in the data you are passing to the carbone.io including the Auth token you got and the templateId for whichever template you want. Mine looks something like this:

{  
    "data": {{qryLineItemsSelect.data}},
    "carboneAuthToken": {{carboneAuthToken.value}},
    "carboneTemplateId": {{carboneInvoiceTemplate.value}}
}

I am just making a simple button that displays an invoice. The button is a material-ui button that doesn’t quite look the the standard retool version but is passable. Replace the entire MyCustomComponent with this:

  const MyCustomComponent = ({ triggerQuery, model, modelUpdate }) => (
        <Button
          color="primary"
          variant="contained"
          size="small"
          fullWidth="true"
          onClick={() => {
        	printInvoice(model.data, model.carboneAuthToken, model.carboneTemplateId)
      	  }}
        >
          Open Invoice
        </Button>
  );

Now you just need a function to do the actual work of making and displaying the PDF. You can put this in the same script block:

async function printInvoice(data, authToken, templateId) {
  const resp = await fetch('https://render.carbone.io/render/' + templateId, {
    method:"POST",
    mode: 'cors',
    body : JSON.stringify({
      "convertTo" : 'pdf',
      "data" : data
    }),
    headers : {
      "content-type": 'application/json',
      "Authorization": 'Bearer ' + authToken,
      "carbone-version": '3',
    }
  }).then(res => res.json());
  if (resp && resp.success === true && resp.data && resp.data.renderId) {
  // Get the result with a simple HTTP GET 
	var newWindow=window.open(`https://render.carbone.io/render/${resp.data.renderId}`, '_blank');
    newWindow.focus(); 
  } else if (resp && resp.error) {
    return (resp.error);
  }
}    

The PDF opens in another tab and sends your eyeballs there!

I cannot seem to get the print dialog working programmatically, window.print() just flashes a blank dialog in Chrome, Edge and FF so that’s kinda weird. If anyone gets that part working, let us know eh?

Also, if you know how to make that button look more seamless please pass that along.

2 Likes

Thank you for that awesome write up!

As for printing, I’m actually not too sure how many options we have built into Retool. All JS is run in a sandbox, so a lot of window functions might not be able to escape out. You could use the utils.downloadFile() or utils.downloadPage() methods built into Retool (docs here: https://docs.retool.com/docs/scripting-retool#utilsdownloadpagefilename--selectorstoexclude-componentstoexclude-scale-fullscreen-). One caveat of downloadPage is that any tables with paginated data would only display the first page so you would need to make the table large enough to fit all of the data.

Would this work for your use case? I assume no, but this is my best guess at the moment. Will write back in if I can find a way to print directly from your app!

utils.downloadFile() is working well with the PDF, just forces extra steps on the user to get it printed.

Thanks. I have not messed with any JS sandboxing so am unfamiliar with it limitations. The iFrame is letting be break free of the sandbox, so I assume you could basically do the same thing I did to get the browser access to the PDF. Of course as I said I was unable to get the print dialog to stick around long enough to actually print, but hopefully I was just ding something wrong.

Not everyone is savvy enough to try and make a custom component to do that job, so I would highly recommend investing some treasure in adding general printing/reporting capabilities to Retool. Maybe integrate Carbone or some other handlebars based framework? I'll do a Feature Request post.

Absolutely. Our PDF handling and printing could use a couple feature requests (which do get read and addressed as we plan our quarters, so you’re not yelling into the void 😅)

In case anyone is here looking for more PDF tools - we've just posted a tutorial here: Tutorial: Making PDF's in Retool But also great to know the info about Carbone!

I am able to get a PDF to export but the sizing is extremely wide and not sure how to lock in the size ratio. My goal is to get a size that can print out on 8.5x11 standard page and also a 4x6 note card. This would be great to figure out and print these items from Retool. Anyone have any thoughts on that? Thanks!

Hi Mhazrat! How are you currently exporting your PDF? I'm not sure if Retool can control the size of the export, unfortunately :pensive:


1 Like

Its been almost a year ,no improvements in pdf and print & it seems that he was yelling into void :sweat_smile: :sweat_smile: . (side not appsmith has the functionality to print your Direct compatitor)

I need the pdf viewer component to be printed directly too (with a print icon to open print dialogue), download then print is NOT a valid option because it is time-critical operation. We need to print 200 invoices in the morning with-in two hours, download then printing is a huge delay and not acceptable.

Yes this is really required to have a good pdf solution to generate nice looking pdf with info from db etc I really need this, without paying more for an API to generate :pensive:

Bumping this internally! Please keep adding +1's to this thread, and thank y'all for already doing so :pray:

9 Likes

Yes it's very important I'm doing a purchase order app I need to generate pdf also stock reports

yes. A built in PDF API would be amazing. I'm just learning Retool but can see many opportunities to use it. I have external PDF API services working, but it feels like a bit of a show-stopper for most of my future usage ideas.

2 Likes

Also wanted to link this thread we did here which might be useful to some of you :slight_smile:

Hey all!

So I have been struggling to find a way to directly print a PDF from retool. The main issue is having to press 2 buttons for every print, including the pop up which you then need to press "Print" on. I have finally found the solution to this. I just wanted to share for anyone that is struggling with printing from retool. I have had great success with Remote Printing for Web Apps | PrintNode. You basically download and install this on any computer connected to any printer, and you will be able to directly print any document from retool with a press of a button. It should be straight forward really. I highly recommend this. If there are problems with implementing this let me know I can write a more detailed instruction on it, but it really is quite simple.