How can I export the <a> tag using pdfhtml5 in DataTables
Problem Description:
I want to export the <a>
tag or link inside a cell in DataTables using pdfhtml5
.
As of now the link is showing as plain text. How can I print it including its format?
Solution – 1
This is a two-step process:
Step 1
Use the DataTables exportOptions.format
function to pass the full HTML text to the PDF maker (instead of just passing the inner text).
exportOptions: {
format: {
body: function ( inner, rowidx, colidx, node ) {
console.log( "in format" );
return inner;
}
}
}
Step 2
Process the PDF document, to convert the HTML <a>
tag into a PDFMake link.
You can use the DataTables customize
function for this.
customize: function ( doc ) {
processDoc(doc);
}
The processDoc
function referenced above is provided below in the runnable demo. It uses JavaScript to extract the link and display text from the HTML. It also adds some styling to make the end result look more like a clickable link.
$(document).ready(function() {
var table = $('#example').DataTable( {
dom: 'Brftip',
buttons: [
{
extend: 'pdfHtml5',
exportOptions: {
format: {
body: function ( inner, rowidx, colidx, node ) {
return inner;
}
}
},
customize: function ( doc ) {
processDoc(doc);
}
}
]
} );
} );
function processDoc( doc ) {
let tableBody = doc.content[1].table.body;
tableBody.forEach(function( row ) {
row.forEach(function( cell ) {
let cellText = cell.text;
if (cellText.startsWith( '<a href=' )) {
let textStart = cellText.indexOf(">") +1;
let textEnd = cellText.indexOf("<", textStart);
let text = cellText.substring(textStart, textEnd);
let linkStart = cellText.indexOf(""") +1;
let linkEnd = cellText.indexOf(""", linkStart);
let link = cellText.substring(linkStart, linkEnd);
cell.text = text;
cell.link = link;
cell.color = '#1a0dab';
cell.decoration = 'underline';
}
});
});
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.12.1/css/jquery.dataTables.css"/>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/buttons/2.2.3/css/buttons.dataTables.css"/>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jszip/2.5.0/jszip.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.12.1/js/jquery.dataTables.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/2.2.3/js/dataTables.buttons.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/2.2.3/js/buttons.html5.js"></script>
<link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">
</head>
<body>
<div style="margin: 20px;">
<table id="example" class="display dataTable cell-border" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon</td>
<td>System Architect</td>
<td><a href="https://en.wikipedia.org/wiki/Edinburgh">Edinburgh</a></td>
</tr>
<tr>
<td>Donna Snider</td>
<td>Customer Support</td>
<td><a href="https://en.wikipedia.org/wiki/New_York_City">New York</a></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
The end result PDF for the above demo looks like this:
Note: If you have other HTML in other columns that you do not want to handle, then you may need to refine your body
function – so, something like:
if ($(node).children('a').length > 0) {
return whatever you need here;
} else {
return inner;
}
Follow-Up Question (from comments):
How about if I have multiple links in one cell? How can I export it?
Yes, there are various ways you can do this.
Since you are already using jQuery (for DataTables), you can use jQuery’s parseHTML()
function. This converts a string of HTML (as text) into an array of the related HTML nodes.
And then you can iterate over the array to process each link one at a time (and also handle any other text which may be in the same data cell).
A basic example:
Let’s assume a DataTable cell containing the following content:
Some text <a href="whateverA">Edinburgh</a> and then <a href="whateverB">New York</a> the end.
The parseHTML()
function will split this into an array containing the following 5 separate nodes – which you can then handle as 5 separate strings:
Some text
<a href="whateverA">Edinburgh</a>
and then
<a href="whateverB">New York</a>
the end.
Here is a demo of that:
let str = 'Some text <a href="whateverA">Edinburgh</a> and then <a href="whateverB">New York</a> the end.'
let nodes = $.parseHTML( str );
nodes.forEach(function( node ) {
if ( node.nodeType === Node.TEXT_NODE ) {
console.log( node.data ); // handle as PDF plain string
} else {
console.log( node.outerHTML ); // handle as PDF link
}
})
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>New tab</title>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
</head>
<body>
<div>See the results in the console, below.</div>
</body>
</html>
Final steps:
Now, instead of creating a PDF cell containing only a single PDF-formatted link, you will need to create an array of 5 PDF elements (see an example here), and add that array to the cell.
myPdfCellContent: [
'Some text ',
{ text: 'Edinburgh', link: 'whateverA' },
' and then ',
{ text: 'New York', link: 'whateverB' },
' the end.'
]
You can integrate this approach into the existing DataTables solution to handle multiple links in one cell.