Table of Contents

Introduction

As a developer, generating downloadable PDF files is very common requirement in SharePoint 2013. While developing SharePoint apps, a developer is faced with couple of questions like, “Do I generate the PDF document client side?”, and “Is it possible to generate PDF documents client side?” The answer is definitely yes, and it’s not that much hard at all. I used the JSPDF library, which has a comprehensive JavaScript API for generating PDF documents.

Solution

Here’s a quick and easy example for generating proposal documents in PDF format.

First of all, create a custom list, and add required columns in that list to store proposal related details (i.e. Title, Project ID, Project Name, Proposed By, Date of Proposal, Description, Start Date, End Date, Price, and Place)

Next, download the JSPDF library files, and copy those files into your SharePoint site. I put them into the Style Library/Custom/PDF/. Then, be sure to include file references inside of your main text file.

<script src="/Style%20Library/Custom/PDF/jquery.min.js"></script>
<script src="/Style%20Library/Custom/PDF/jspdf.min.js"></script>
<script src="/Style%20Library/Custom/PDF/FileSaver.js"></script>








Now, let’s generate a PDF document. You can try below code snippet in CEWP on display form of list that will add a button in ribbon to generate a very simple PDF document and save it to the local file system.















$(document).ready(function() {
    // To add print button in ribbon
 
    var linkButton = '<span class="ms-cui-ctl-largeIconContainer" unselectable="on"><span class=" ms-cui-img-32by32 ms-cui-img-cont-float ms-cui-imageDisabled" unselectable="on"><img class="" style="top: -409px;left: -239px;" unselectable="on" src="/_layouts/15/1033/images/formatmap32x32.png?rev=40"></span></span><span class="ms-cui-ctl-largelabel" unselectable="on">Print<br>Item</span>'
    var editLink = document.getElementById("Ribbon.ListForm.Display.Manage.EditItem-Large");
    var node = document.createElement("A");
    node.text = "Print Item";
    node.className = "ms-cui-ctl-large";
    node.innerHTML = linkButton;
    node.onclick = function() {
        printTable(this);
        return false;
    };
    editLink.parentNode.appendChild(node);
});
 
var objSender;
var fileName;
 
function printTable(sender) {
    // To generate pdf document using list item data 
 
    objSender = sender;
    var promise = $.ajax({
        url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('Proposal Details')/items('" + getParameterByName('ID') + "')",
        method: "GET",
        headers: {
            "ACCEPT": "application/json;odata=verbose"
        }
    });
 
    promise.done(successFunction);
    promise.fail(errorFunction);
}
 
function successFunction(data) {
    l = {
        orientation: 'p',
        unit: 'px',
        format: 'a4',
        compress: true,
        fontSize: 28,
        lineHeight: 0,
        autoSize: true,
        printHeaders: true
    };
 
 
    var imgLogo = 'data:image/png;base64,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'
 
    var varHeight = 100; // Starting point from the top
 
    var doc = new jsPDF(l, 'px', 'a4', true),
        sizes = [12],
        fonts = [
            ['Helvetica', '']
        ],
        font, size, lines, margin = 0.5,
        verticalOffset = margin,
        loremipsum = data.d.Description;
 
    doc.addImage(imgLogo, 'JPEG', 38, 35, 53, 40)
 
    doc.setFontSize(12);
    doc.setTextColor(0, 114, 198);
    doc.setFontType("bold");
    doc.text(40, varHeight + 2, data.d.Title);
 
    doc.setFontSize(9);
    doc.setTextColor(0, 0, 0);
 
    // first table
 
    doc.line(40, varHeight + 20, 410, varHeight + 20);
    doc.line(40, varHeight + 32, 410, varHeight + 32);
    doc.line(40, varHeight + 44, 410, varHeight + 44);
    doc.line(40, varHeight + 20, 40, varHeight + 44);
    doc.line(110, varHeight + 20, 110, varHeight + 44);
    doc.line(250, varHeight + 20, 250, varHeight + 44);
    doc.line(330, varHeight + 20, 330, varHeight + 44);
    doc.line(410, varHeight + 20, 410, varHeight + 44);
 
    // first table data
    doc.text(50, varHeight + 29, 'Project name');
    doc.text(260, varHeight + 29, 'Project ID');
    doc.text(50, varHeight + 41, 'Proposed by');
    doc.text(260, varHeight + 41, 'Date of proposal');
 
    doc.setFontType("normal");
    doc.text(120, varHeight + 29, data.d.Project_x0020_Name);
    doc.text(340, varHeight + 29, data.d.Project_x0020_ID);
    doc.text(120, varHeight + 41, data.d.Proposed_x0020_By);
    doc.text(340, varHeight + 41, data.d.Date_x0020_Of_x0020_Proposal);
 
    doc.setFontSize(12);
    doc.setTextColor(0, 114, 198);
    doc.setFontType("bold");
    doc.text(40, varHeight + 80, 'GENERAL DESCRIPTION');
 
    doc.setFontSize(9);
    doc.setTextColor(0, 0, 0);
 
    font = fonts[0];
    size = sizes[0];
    doc.setFontType("normal");
    lines = doc.setFont().setFontSize(size).splitTextToSize(loremipsum, 375);
    doc.text(40, varHeight + 95 + verticalOffset + size / 72, lines);
    verticalOffset += (lines.length + 0.5) * size / 72;
 
    varHeight += lines.length * 8 + 10;
    doc.setFontSize(12);
    doc.setTextColor(0, 114, 198);
    doc.setFontType("bold");
    doc.text(40, varHeight + 125, 'PRICING AND SCHEDULE');
 
    doc.setFontSize(9);
    doc.setTextColor(0, 0, 0);
   
    // second table
   
    doc.line(40, varHeight + 140, 410, varHeight + 140);
    doc.line(40, varHeight + 152, 410, varHeight + 152);
    doc.line(40, varHeight + 164, 410, varHeight + 164);
    doc.line(40, varHeight + 140, 40, varHeight + 164);
    doc.line(163, varHeight + 140, 163, varHeight + 164);
    doc.line(286, varHeight + 140, 286, varHeight + 164);
    doc.line(410, varHeight + 140, 410, varHeight + 164);
 
    // second table data
   
    doc.text(50, varHeight + 149, 'Start Date');
    doc.text(173, varHeight + 149, 'End Date');
    doc.text(296, varHeight + 149, 'Payment in USD');
 
    doc.setFontType("normal");
    doc.text(50, varHeight + 161, data.d.Start_x0020_Date);
    doc.text(173, varHeight + 161, data.d.End_x0020_Date);
    doc.text(296, varHeight + 161, data.d.Price);
 
    // footer part
   
    doc.text(40, varHeight + 200, 'Place and date');
    doc.text(40, varHeight + 210, 'In ' + data.d.Place + '  ' + convertDate(new Date()));
    doc.text(40, varHeight + 220, data.d.Client);
   
    // save document to the local file system.
 
    doc.save("Test.pdf");
}
 
function errorFunction(error) {
    var errText = $.parseJSON(error.responseText);
    alert(errText.error.message.value);
}
 
function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
    var regexS = "[\\?&]" + name + "=([^&#]*)";
    var regex = new RegExp(regexS);
    var results = regex.exec(window.location.search);
    if (results == null)
        return "";
    else
        return decodeURIComponent(results[1].replace(/\+/g, " "));
}
 
function convertDate(inputFormat) {
    function pad(s) {
        return (s < 10) ? '0' + s : s;
    }
    var d = new Date(inputFormat);
    return [pad(d.getDate()), pad(d.getMonth() + 1), d.getFullYear()].join('/');
}








Above script gives us very grateful output something like below.















Be sure to check out the JSPDF online examples for more details.

Code Download

You can download the code snippet here that is used to generate the PDF file.