Simple PDF report
Matrix (tabular) report
Master–Detail PDF report
The video focuses on structuring data properly and rendering it into well-formatted PDF documents using jsPDF, making it useful for ERP, reporting, and web application scenarios.
This tutorial is ideal for developers who want to implement client-side PDF generation and build professional reports directly from JavaScript.
JavaScript File URLs
https://cdnjs.cloudflare.com/ajax/libs/ ... umd.min.js
https://cdnjs.cloudflare.com/ajax/libs/ ... ble.min.js
If you want to download then you can right click above links and then save as to download and upload in Oracle APEX static files in APP or Workspace level and then using those links. You can further check the version if you are comfortable to make any update might required.
Function and Global Variable Declaration
Code: Select all
apex.jQuery(function () {
/* =====================================================
Shared logo loader (HTML image from Workspace Files)
===================================================== */
const logoUrl = '#WORKSPACE_FILES#erpstuff_logo_small.png';
const logoImg = new Image();
logoImg.src = logoUrl;
// Utility function: wait for image to load before generating PDF
function waitForLogoAndRun(callback) {
if (!logoImg.complete) {
logoImg.onload = callback;
} else {
callback();
}
}
/* =====================================================
DEPARTMENT-WISE EMPLOYEE PDF
===================================================== */
window.generatePDF = function () {
waitForLogoAndRun(() => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'pt', 'a4');
const rawData = JSON.parse($v("P34_JSON"));
const pageWidth = doc.internal.pageSize.getWidth();
const pageHeight = doc.internal.pageSize.getHeight();
const drawHeader = () => {
doc.addImage(logoImg, 'PNG', 20, 10, 60, 40);
doc.setFontSize(18);
doc.setFont(undefined, 'bold');
doc.text('Employee Report', pageWidth / 2, 40, { align: 'center' });
};
const drawFooter = () => {
const pageNum = doc.getCurrentPageInfo().pageNumber;
const pageCount = doc.getNumberOfPages();
doc.setFontSize(10);
doc.text(`Page ${pageNum} of ${pageCount}`, pageWidth - 80, pageHeight - 20);
};
rawData.forEach((dept, index) => {
if (index > 0) doc.addPage();
drawHeader();
doc.autoTable({
startY: 60,
head: [['Emp No', 'Name', 'Job', 'Salary', 'Comm']],
body: dept.employees.map(e => [
e.empno,
e.ename,
e.job,
e.sal,
e.comm || 0
]),
theme: 'grid',
styles: { fontSize: 10 },
didDrawPage: () => {
drawHeader();
drawFooter();
}
});
});
window.open(doc.output('bloburl'));
});
};
/* =====================================================
JOB × LOCATION MATRIX PDF
===================================================== */
window.generateMatrixPDF = function () {
waitForLogoAndRun(() => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('l', 'pt', 'a4');
const rawData = JSON.parse($v("P34_JSON2"));
const pageWidth = doc.internal.pageSize.getWidth();
const jobs = [...new Set(rawData.map(r => r.job))];
const locs = [...new Set(rawData.map(r => r.loc))];
const head = [['JOB', ...locs]];
const body = jobs.map(job => {
const row = [job];
locs.forEach(loc => {
const rec = rawData.find(r => r.job === job && r.loc === loc);
row.push(rec ? rec.cnt : 0);
});
return row;
});
const drawHeader = () => {
doc.addImage(logoImg, 'PNG', 20, 10, 60, 40);
doc.setFontSize(18);
doc.setFont(undefined, 'bold');
doc.text('Employee Count Matrix', pageWidth / 2, 40, { align: 'center' });
};
drawHeader();
doc.autoTable({
startY: 70,
head: head,
body: body,
theme: 'grid',
styles: { fontSize: 10, halign: 'center' },
columnStyles: { 0: { halign: 'left' } }
});
window.open(doc.output('bloburl'));
});
};
/* =====================================================
MASTER-DETAIL PDF
===================================================== */
window.generateMasterDetailPDF = function () {
waitForLogoAndRun(() => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'pt', 'a4');
const data = JSON.parse($v("P34_JSON_MD"));
const pageWidth = doc.internal.pageSize.getWidth();
const pageHeight = doc.internal.pageSize.getHeight();
const drawHeader = () => {
doc.addImage(logoImg, 'PNG', 20, 10, 60, 40);
doc.setFontSize(18);
doc.setFont(undefined, 'bold');
doc.text('Master-Detail Employee Report', pageWidth / 2, 40, { align: 'center' });
};
const drawFooter = () => {
const pageNum = doc.getCurrentPageInfo().pageNumber;
const pageCount = doc.getNumberOfPages();
doc.setFontSize(10);
doc.text(`Page ${pageNum} of ${pageCount}`, pageWidth - 80, pageHeight - 20);
};
data.forEach((dept, idx) => {
if (idx > 0) doc.addPage();
drawHeader();
// Master info
doc.setFontSize(14);
doc.setFont(undefined, 'bold');
doc.text(`Department: ${dept.dname} (${dept.deptno})`, 40, 70);
// Detail table
doc.autoTable({
startY: 80,
head: [['Emp No', 'Name', 'Job', 'Salary']],
body: dept.employees.map(e => [e.empno, e.ename, e.job, e.sal]),
theme: 'grid',
styles: { fontSize: 10 },
didDrawPage: () => {
drawHeader();
drawFooter();
}
});
});
window.open(doc.output('bloburl'));
});
};
});
https://youtu.be/q8YNqKuZ6sc