Printing a webpage with PDF Core

The second way that you can upload a pdf to the server is creating a pdf from an html string. While technically, this can be any HTML string, most commonly, this will be printing a page to a pdf. Unfortunately, this string must be raw HTML (no handlebars is allowed), so if you are attempting to print a page, some extra work needs to be done to make sure everything renders properly in the PDF file. This documentation takes you through step by step how to do this.

Server Side

There are several pdf-core functions built in to help you, but you are not able to call them directly from the client side, as there is likely some minimal set up you will need to do before printing a pdf.

PdfController.php File

Navigate to the controller file for the current page you are on (in this example, we will use the generic PdfController). At the top of the controller file, you need to have the following line of code because otherwise it won’t know where to find the correct PDF Class:

use PdfCore\PdfUtils;

After this, we need two functions to be defined because the built in pdf-inline view has to be called in its own request in order to open in a new tab properly. So first you need the actual "print" function:

public function printPdf($object) {
    //function data
}

Whatever formatting you want to do is fine, but in order to save the html, just call the this function: PdfUtils::savePdfFromHTML(string $htmlString, string $fileName, array $options). The three parameters are as follows:

  • htmlString -> Basically a simple string with all of the html that you wish to print. This can be modified after being passed to the serverside from the client in php if you so choose. Additionally, this function uses the TCPDF writeHTML function, which has recognizes limited HTML. See discussion in TCPDF limited HTML recognizing capacity. This is discussed in more detail under Designing with TCPDF, when we speak about the writeHTML function, which can be found here.

  • fileName -> this is the name of the file you wish to save it under, usually this will be saved in the pdfDirectory until it is overridden with another print

  • options -> this is simply an array of the settings, that you wish to place in the header of the pdf. The only valid keys for the options are: creator, author, title, subject, keywords (should be an array), or font.

Example

Here is a practical example of what this might look like for your code:

$html = $object['html'];
$optionsArray = ['creator' => $this->user->get('id'),
                'author' => 'Benner Library Pdf Printer',
                'font' => ['family' => 'Times', 'size' => 12]];

PdfUtils::savePdfFromHTML($html, "toPrint.pdf", $optionsArray);

After this is saved, there is one more function you need, and that is how to download or preview the page that you just made (with print from HTML, typically we use "preview" not "download"). But this is covered in the PDF Views document, so you will have to finish that there.

Router.php

Now that you have both of your functions defined, you need to add both of them to your serverside routes, so they can be accessible from the client side. That is fairly simple, just find the generateRouteGroup function for your Controller, and add in the custom routes. In the end it should look like this (note: don’t delete any other custom routes, just add these to the array, or make a new array if there isn’t any):

// Whatever method you are using whether preview or download should be listed in the Router as well
$this->generateRouteGroup('pdfController', [
    ['/printPdf/', 'printPdf', 'POST'],
    ['/printPreviewPdf/', 'printPreviewPdf', 'GET', false]
], true);

Client Side

PDF core takes a simple html string and formats it as a pdf, saves the pdf to a server directory, displays the pdf, then deletes the temporary pdf. Because of this, all your clientside needs to do is send a string full of HTML to the server.

HTML/HBS

A couple of notes about the type of HTML to use:

  • Since we will be using a pdf, none of our css will work. The classes are defined for the webpage, but are not embedded into any pdf we create, so any css you want to have printed will need to be accomplished through inline css (eg style attribute) or just be dependent on HTML Tags.

  • Handlebars code is just a fancy wrapping for vanilla HTML, so any handlebars code or custom components will display properly (just make sure to also check the component for css as well, as that will have to be properly represented)

  • Since CSS is used on a regular basis within the app, if CSS is needed to actually be printed, it may be that you need to define a separate print div to easily simplify and more specifically format the type of code that will be printed within the PDF. If you do this, make sure to hide the div element with the hidden attribute:

    <div hidden=true id="printableDiv">
        ...
    </div>
  • Last note for the HTML, make sure to properly display id within whatever div you want to print (see above). This is needed whether you are making a new hidden "printDiv" or if you are just printing the text off of a part of the page.

Javascript

Now that you have a properly formatted div element for printing move over to your client side. (In order to set up your action correctly, make sure that you have the config, and ajax services injected correctly).

Within the javascript function you are using to print (probably you will have a HTML button with an action), you just need the following line of code:

    let html = document.getElementById(idName).innerHTML;

Where idName is whatever you titled the id of the printing div. In the example given above, idName would be 'printableDiv'. For more documentation on the various uses of the document interface in Javascript click here.

Now all you have to do is pass the string html to the serverside for further processing, which can be done by the following lines of code:

let printUrl = this.get('config').formUrl('pdfController', 'printPdf');

return RSVP.resolve(this.get('ajax').request(printUrl, {data:{html}}).then(() => {
    //since preview was the desired outcome, the preview function needs to be called separately
    let previewUrl = this.get('config').formUrl('pdfController', 'previewPdf');
    window.open(previewUrl, '_blank');
});

Basically, all these lines of code are doing is sending the html to the function printPdf, which will properly save it as a pdf to the server, then after that function is successful, it opens a new tab with the generated pdf (for more documentation on the window.open function click here)