PDF report package
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.
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.

Packages workspace
Note: you can also use the command palette to find the Create package action.
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
};
}
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.
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.
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);
}
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.

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.
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 ofpage
elements in thetemplate.handlebars
file, otherwise the PDF will not correctly render.
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 modified 6mo ago