I have a solution in a system for group reporting where I have a selected number of datatables rendered out of view and I provide download links to each table, i.e.:
let singlePDFdownload = function (table_id) {
$(`.toolbar${table_id} .custom-pdf`).trigger('click')
}
This works fine for single downloads, but I also want to enable a quick button so all downloads can be generated at once. I currently do this with the .custom_pdf
class so I can group the buttons that execute the datatable export of said table. This is a problem with the way I currently have this, because it initiates multiple downloads in the browser with multiple pop-ups (occasionally showing a warning).
How do I go about combining those 'clicks' into a single download?
Can I capture the download that occurs because of the trigger('click;)
and then combine the PDFs somehow in a zipped folder, or how can this be accomplished?
Here is the code that triggers the multiple downloads:
const $massPDFExport = $('#massPDFExport')
$massPDFExport.on('click', () => {
// remember all tables shown have this class
$(`.custom-pdf`).trigger('click')
})
Here is a fully reproducible example:
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/buttons/2.3.6/css/buttons.dataTables.min.css">
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.print.min.js"></script>
<script>
$(document).ready(function () {
$('#example_1').DataTable({
dom: 'Bfrtip',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
]
});
$('#example_2').DataTable({
dom: 'Bfrtip',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
]
});
$('#export_all').on('click', () => {
$('.buttons-pdf').each(function (a) {
console.log(9888)
$(this).trigger("click");
});
});
});
</script>
<a id='export_all' class=''> Export All As PDF</a>
<table id="example_1" class="display nowrap" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011-04-25</td>
<td>$320,800</td>
</tr>
<tr>
<td>Garrett Winters</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011-07-25</td>
<td>$170,750</td>
</tr>
</tbody>
</table>
<table id="example_2" class="display nowrap" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011-04-25</td>
<td>$320,800</td>
</tr>
<tr>
<td>Garrett Winters</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011-07-25</td>
<td>$170,750</td>
</tr>
</tbody>
</table>
I figured out a solution and figured I would post an answer showing an easy example of how to combine and zip multiple PDF files using datatables, JSZip, and PDfMake since I could not find many real examples of it.
Overall it came down to the customize
option for button definitions.
buttons.pdf.js
function customPdfButtonAction (e, dt, button, config) {
this.processing(true);
var that = this;
var data = dt.buttons.exportData(config.exportOptions);
var info = dt.buttons.exportInfo(config);
var rows = [];
if (config.header) {
rows.push(
$.map(data.header, function (d) {
return {
text: typeof d === "string" ? d : d + "",
style: "tableHeader"
};
})
);
}
for (var i = 0, ien = data.body.length; i < ien; i++) {
rows.push(
$.map(data.body[i], function (d) {
if (d === null || d === undefined) {
d = "";
}
return {
text: typeof d === "string" ? d : d + "",
style: i % 2 ? "tableBodyEven" : "tableBodyOdd"
};
})
);
}
if (config.footer && data.footer) {
rows.push(
$.map(data.footer, function (d) {
return {
text: typeof d === "string" ? d : d + "",
style: "tableFooter"
};
})
);
}
var doc = {
pageSize: config.pageSize,
pageOrientation: config.orientation,
content: [
{
table: {
headerRows: 1,
body: rows
},
layout: "noBorders"
}
],
styles: {
tableHeader: {
bold: true,
fontSize: 11,
color: "white",
fillColor: "#2d4154",
alignment: "center"
},
tableBodyEven: {},
tableBodyOdd: {
fillColor: "#f3f3f3"
},
tableFooter: {
bold: true,
fontSize: 11,
color: "white",
fillColor: "#2d4154"
},
title: {
alignment: "center",
fontSize: 15
},
message: {}
},
defaultStyle: {
fontSize: 10
}
};
if (info.messageTop) {
doc.content.unshift({
text: info.messageTop,
style: "message",
margin: [0, 0, 0, 12]
});
}
if (info.messageBottom) {
doc.content.push({
text: info.messageBottom,
style: "message",
margin: [0, 0, 0, 12]
});
}
if (info.title) {
doc.content.unshift({
text: info.title,
style: "title",
margin: [0, 0, 0, 12]
});
}
if (config.customize) {
config.customize(doc, config, dt);
}
var pdf = window.pdfMake.createPdf(doc);
if (config.download === "open" && !_isDuffSafari()) {
pdf.open();
} else {
// In case of silent mode — exit without downloading
if (e.detail.silent) return this.processing(false);
pdf.download(info.filename);
}
this.processing(false);
}
window.customPdfButtonAction = customPdfButtonAction
main_functionality.js
(function ($) {
let PDF_BLOB_PROMISES = [];
const buttons = [
"copy",
"csv",
"excel",
"print",
{
extend: "pdf",
text: "PDF",
customize: customPDFButtonCustomize, // here is the key
action: customPdfButtonAction // here is the key
}
]
// Push Blob to array of Promises
async function customPDFButtonCustomize(doc) {
try {
PDF_BLOB_PROMISES.push(
new Promise((resolve, reject) => {
window.pdfMake.createPdf(doc).getBlob(resolve);
})
);
} catch (e) {
console.error("Push PDF to Blob failed", e);
}
}
// Init Data tables
function initDT() {
$('[data-type="dt"]').each(function (i) {
const table = $(this).DataTable({
buttons
});
table
.buttons()
.container()
.appendTo(`#DataTables_Table_${i}_wrapper .col-md-6:eq(0)`);
});
}
// Export All button handler
async function exportAllPDF() {
try {
const zip = new window.JSZip();
const folder = zip.folder("pdf");
PDF_BLOB_PROMISES = [];
$(".buttons-pdf").each(function (a) {
const event = new CustomEvent("click", {
detail: {
silent: true
}
});
this.dispatchEvent(event);
});
const blobs = await Promise.all(PDF_BLOB_PROMISES);
if (!blobs.length) return;
for (let i = 0; i < blobs.length; i++) {
folder.file(`pdf-${i + 1}.pdf`, blobs[i]);
}
const zipped = await zip.generateAsync({ type: "blob" });
window.saveAs(zipped, "pdfs.zip");
} catch (e) {
console.error("Eport All PDF failed", e);
}
}
$(document).ready(function () {
// Init Data Tables
initDT();
// Export All button event listener
$("#export_all").on("click", exportAllPDF);
})
})(window.jQuery)
HTML Page
<!DOCTYPE html>
<html>
<head>
<title>Show Me Some Magic</title>
<meta charset="UTF-8" />
<!-- CSS -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.2/css/bootstrap.css"
/>
<link
rel="stylesheet"
href="https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap4.min.css"
/>
<link
rel="stylesheet"
href="https://cdn.datatables.net/buttons/2.3.6/css/buttons.bootstrap4.min.css"
/>
<style>
body {
padding: 2rem;
}
.dataTables_wrapper {
margin-bottom: 3rem;
}
.btn-export-all {
background: #afddff;
border-radius: 10px;
border: none;
padding: 10px 20px;
cursor: pointer;
}
</style>
<!-- VENDOR JS -->
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/dataTables.bootstrap4.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.bootstrap4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.print.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.colVis.min.js"></script>
<!-- Local JS -->
<script src="./js/buttons.pdf.js"></script>
<script src="./js/main_functionality.js"></script>
</head>
<body>
<div style="padding: 20px 0;">
<button id="export_all" class="btn-export-all">Export All As PDF</button>
</div>
<table data-type="dt" class="table table-striped table-bordered compact">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon 1</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011-04-25</td>
<td>$320,800</td>
</tr>
<tr>
<td>Garrett Winters 1</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011-07-25</td>
<td>$170,750</td>
</tr>
</tbody>
</table>
<table data-type="dt" class="table table-striped table-bordered compact">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon 2</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011-04-25</td>
<td>$280,800</td>
</tr>
<tr>
<td>Garrett Winters 2</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011-07-25</td>
<td>$590,750</td>
</tr>
</tbody>
</table>
</body>
</html>