I have an HTML in Google App Scripts web app that contains a table that might span over several pages, and I want to add page numeration at the bottom right of each page, something like "Page 3/4". The page numeration should include the current page and the total amount of pages.
This is a simple test code that reproduces the issue.
Script:
function doPost(e) {
try {
const template = HtmlService.createTemplateFromFile('test');
const tableData = [];
for (i = 0; i < 100; i ++) { // 100 could be any number
tableData.push({ code: 1, product: 'shampoo'});
}
template.tableRows = tableData;
const htmlOutput = template.evaluate().getContent();
const pdfBlob = Utilities.newBlob(htmlOutput, 'text/html').getAs('application/pdf');
pdfBlob.setName('some.pdf');
const pdfBytes = pdfBlob.getBytes();
const pdfBase64 = Utilities.base64Encode(pdfBytes);
console.log(pdfBase64)
return ContentService.createTextOutput(JSON.stringify({ pdf: pdfBase64 })).setMimeType(ContentService.MimeType.JSON);
} catch (error) {
console.error(error)
return ContentService.createTextOutput().setMimeType(ContentService.MimeType.JSON);;
}
}
test.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<style>
@page {
size: A4;
margin: 0;
counter-increment: page;
}
.page-footer {
position: fixed;
bottom: 0;
right: 0;
margin: 10px;
font-size: 10px;
}
.page-footer::after {
content: counter(page);
}
</style>
<body>
<table>
<thead>
<tr>
<th>Code</th>
<th>Product</th>
</tr>
</thead>
<tbody>
<? tableRows.forEach(function (item) { ?>
<tr>
<td>
<?= item.code ?>
</td>
<td>
<?= item.product ?>
</td>
</tr>
<? }); ?>
</tbody>
<div class="page-footer"></div>
</body>
</html>
This code produces a "0" at the bottom right at the end of each page, instead of the expected page numeration (i.e. 1, 2, 3, etc...).
How can I add automatic page numeration in this process of PDF generation from an html template?
Here is a workaround! I tried your code
and encountered a problem, I researched CSS - Footer Page Counter
and it seems not to be working.
I also modified for loop
in your code, added some variables with limit per page andDriveApp
where the pdf will be saved. I also included pdf merger Merging PDF Files in Google Drive using Google Apps Script.
Sample Output:
Code.gs
const folderId = "--Folder Id --";
async function combinePDFs(childFolderId) {
const parentFolder = DriveApp.getFolderById(folderId);
const childFolder = DriveApp.getFolderById(childFolderId);
const files = childFolder.getFiles();
// Merge PDFs.
const cdnjs = "https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js";
eval(UrlFetchApp.fetch(cdnjs).getContentText()); // Load pdf-lib
const setTimeout = function (f, t) {
Utilities.sleep(t);
return f();
}
const pdfDoc = await PDFLib.PDFDocument.create();
while (files.hasNext()) {
const file = files.next();
Logger.log(file.getName() + ' ' + file.getMimeType());
if (file.getMimeType() === 'application/pdf') {
const pdfData = await PDFLib.PDFDocument.load(new Uint8Array(file.getBlob().getBytes()));
const pages = await pdfDoc.copyPages(pdfData, [...Array(pdfData.getPageCount())].map((_, i) => i).sort());
pages.forEach(page => pdfDoc.addPage(page));
}
}
const bytes = await pdfDoc.save();
// Create a PDF file.
parentFolder.createFile(Utilities.newBlob([...new Int8Array(bytes)], MimeType.PDF, "Merged.pdf"));
childFolder.setTrashed(true);
}
function doPost() {
try {
const parentFolder = DriveApp.getFolderById(folderId);
const createChildFolder = parentFolder.createFolder("TempFiles").getId();
const template = HtmlService.createTemplateFromFile('test');
let tableData = [];
const limit = 20; // Limit per page.
const totalData = 100; // Total Data.
const equation = totalData - Math.round((limit * (totalData / limit)));
let page = Math.round(totalData / limit) + 1;
for (i = 1; i < totalData + 1; i++) {
tableData.push({ code: 1, product: 'shampoo' });
if (i % limit === 0) {
createPdf()
} else if (i > (totalData - equation) && tableData.length === equation) {
createPdf();
}
}
function createPdf() {
template.tableRows = tableData;
template.pages = page -= 1;
const htmlOutput = template.evaluate().getContent();
const pdfBlob = Utilities.newBlob(htmlOutput, 'text/html').getAs('application/pdf');
pdfBlob.setName(`some${page}.pdf`);
uploadFile(pdfBlob, createChildFolder);
tableData = []
console.log(page);
}
combinePDFs(createChildFolder)
} catch (error) {
console.error(error)
return ContentService.createTextOutput().setMimeType(ContentService.MimeType.JSON);;
}
}
function uploadFile(pdf, childFolder) {
const folder = DriveApp.getFolderById(childFolder);
const file = folder.createFile(pdf);
file.setDescription("Temp Pdf");
console.log("File Uploaded!");
}
test.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<style>
@page {
size: A4;
margin: 0;
}
.page-footer {
position: fixed;
bottom: 0;
right: 0;
margin: 10px;
font-size: 10px;
}
</style>
<body>
<table>
<thead>
<tr>
<th>Code</th>
<th>Product</th>
</tr>
</thead>
<tbody>
<? tableRows.forEach(function (item) { ?>
<tr>
<td>
<?= item.code ?>
</td>
<td>
<?= item.product ?>
</td>
</tr>
<? }); ?>
</tbody>
<div class="page-footer">
<?= pages ?>
</div>
</body>
</html>
References: