PDF report package

Guide

Here we’ll take you through the steps to generate a custom PDF report with dynamic data and displaying it in your TypeScript app, using app packages and the <html/> UI component. An added advantage of using app packages for this use case is the ability to generate those PDFs while in offline mode.

The "PDF Report" TypeScript app template which you can select upon creating an app contains the foundations for this example case. You can use it to follow along and as a template to build upon.

1. Add the PDF Report template package to your app

Navigate to the Packages workspace, or open the Packages panel, and create a new package. In the Package template dropdown, select "PDF Report" and proceed to follow the prompts. This created an app package with a basic framework to generate custom PDF reports.

Note: you can also use the command palette to find the Create package action.

2. Preparing the data to populate the report template

We’ll want to use some data from the app’s database in the PDF report. Open the getData.ts file, which you can find by navigating to src/template/ inside the newly created package.

Modify the getData function to the following to retrieve the first user from the database:

export async function getData(db: any) {
    const firstUser: any = await db.user.first();
    return {
        user: firstUser
    };
}

3. Pulling data into the PDF report

Next, we want to display the user’s name within the PDF report. Open the template.handlebars file which is also located inside the src/template/ folder.

Modify the content of the file to the following:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <page size="A4-Portrait">
            <h1>Hello {{user.name}}</h1>
    
            <footer>1 of 1</footer>
        </page>
    </body>
</html>

Note that in this example Handlebars is used as a templating language, but you should also be able to use other templating systems.

4. Customizing the look and feel of the PDF report

This template also allows us to easily customize the style of the PDF. Let’s update the heading style as a simple example. Open the custom.scss file which is located in the src/template/scss folder.

Modify the content of the file to the following:

// ############ Custom ##############
// Use this space for some custom css to use in PDF
h1 {
  color: blue;
}

Now, perform a global testing deploy (CTRL+S / CMD+S) or fire the Deploy to testing action to build this package.

5. Adding the component to your view

In this example, we will display this PDF report inside the main view of our app. Navigate to your main view, and update the view’s XML and TypeScript to the following:

<?xml version="1.0" encoding="UTF-8"?>
<view title="Home">
    <html src="@local/hello_world_report/index.html" id="pdf" height="600" show-fullscreen-button="true"/>
    <button label="Generate PDF" on-press="generatePdf" validate="false" />
</view>
import { getData } from "@local/hello_world_report"

// This function is called when the app navigates to this view (using a link)
async function init() {
    // initialize any data here that should be available when the view is shown
}

// This function is called when the user returns to this view from another view
async function resume(from: ResumeFrom) {}

async function generatePdf() {
    let data = await getData(DB);
    component.html({ id: 'pdf' }).post('generatePDF', data);
}

6. Viewing the generated PDF report inside the app

Perform a testing deploy and then test your app to view the PDF report in-app. Fire the Test app action and follow the subsequent prompts. The landing page in your app should contain a container which is empty at first, and after pressing the “Generate PDF” button inside the view, the PDF should display as follows.

7. Local development (CLI)

Local development is only supported for GitHub apps.

There may be cases where you want to make updates to this package locally. For example, to speed up the feedback loop between making updates and viewing those updates. We have released a CLI tool for this purpose.

Note: The CLI tool is currently optimized for PDF reports. In the near future we will be expanding upon this to include other use cases, e.g. custom <html/> components.

Your app needs to be linked to GitHub to make use of the CLI tool. The following steps in this guide assume that you have your app’s repo cloned locally and have yarn installed.

To make updates locally, and instantly review updates in your web browser, follow these steps:

  1. Run yarn install in the root folder of your PDF report package: hello_world_report git:(master) yarn install. This installs, among other things, the JourneyApps PDF CLI tool which you will use in the following steps.

  2. Run yarn pdf init to initialize the PDF CLI functionality for this package, and follow the next prompts to connect to your app’s database.

  3. Run yarn pdf watch to display the compiled PDF in your browser. Any changes made to the PDF will refresh the browser window. You can now proceed to make updates to your PDF and review the result instantly.

FAQs

How can I download the PDF report?

To download the PDF, you can call the downloadPDF method on the HTML client after you have generated the PDF:

async function generatePdf() {
    const data = await getData(DB);
    component.html({ id: 'pdf' }).post('generatePDF', data);
}

async function downloadPdf() {
    await generatePdf();

    const options = {
        fileName: 'test.pdf', // User specified name of the file
        pageOrientation: 'portrait', // landscape | portrait
        platform: 'windows', // Specify the platform used by the the app user: windows | android.  "windows" can be used for any supported desktop device. 
        htmlElements: ['page-1'], // Specify the ids of the pages in the template.handlebars file to be included in this file export
    };

    component.html({ id: 'pdf' }).post('downloadPDF', options);
}
  • Downloading the PDF report is not currently supported on iOS.

  • For the htmlElements option, only include ids of page elements in the template.handlebars file, otherwise the PDF will not correctly render.

How can I save the PDF report to the backend?

To save the report to the backend, you can use the compilePDF method on the HTML client, in combination with the compiledData method.

First, include the compiledData event to the view TypeScript:

component.html({ id: "pdf" }).on("compiledData", async function (data: any) {
    view.pdfFile = await Attachment.create({ filename: "test.pdf", base64: data.raw });    
});

Next, add the compilePDF method in the same way as the downloadPDF method described above:

async function generatePdf() {
    const data = await getData(DB);
    component.html({ id: 'pdf' }).post('generatePDF', data);
}

async function savePdf() {
    await generatePdf();

    const options = {
        fileName: 'test.pdf', // User specified name of the file
        pageOrientation: 'portrait', // landscape | portrait
        platform: 'windows', // Specify the platform used by the the app user: windows, android or ios
        htmlElements: ['page-1'], // Specify the ids of the pages in the template.handlebars file to be included in this file export
    };

    component.html({ id: "pdf" }).post("compilePDF", options);
}

Last updated