Record Producer with a fillable PDF widget

Mauricio G Raud
Tera Expert

Hi,

I have a requirement to create an interaction/case from the CSM service portal, in this record producer I need to give the user a pre-filled PDF, and keep the ability to keep filling the rest of the PDF, after the user has completed that then this PDF has to be attached to the record created and trigger a download for the user.

 

I was able to add the PDF to the record producer with a custom widget that fetches the attachment data, fills some fields in it using PDF-lib (https://pdf-lib.js.org/), and displays it inside the record producer. 

I still need to get this data saved so I can attach the resulting PDF to the record and trigger download. Any help is appreciated here.

I know one way to approach this is to create variables in the record producer and map them to the PDF using PDFGenerationAPI, but the client didn't accept this, the requirement is prepopulate the PDF, allow edits from the user and save it. 

 

For simplicity take this record producer configured with only 2 variables: one mapped to short_description and the other is the custom widget. 

 

RP with custom widget

PDF populated with data from server side, using PDF-lib

 

The widget takes some code and the pdf template from PDF-lib site, also this is a simpler version of the actual widget but the idea is the same.

 

HTML template:

<div>

  <h2>Generate PDF</h2>
  <button class="btn btn-primary" ng-click="c.generatePdf()">Generate PDF</button>
  <div ng-if="c.pdfUrl">
    <iframe id="custom_pdf_view" ng-src="{{c.pdfUrl}}" width="100%" height="600px"></iframe>
  </div>
  
</div>

 Client Controller:

api.controller = function($scope, $sce, $window, spUtil) {
    /* widget controller */
    var c = this;

    this.generatePdf = async function() {
        const {
            PDFDocument
        } = PDFLib;

        const pdfDoc = await PDFDocument.load(c.data.pdfBase64);
        
        const form = pdfDoc.getForm();
        
        const firstName = form.getTextField('Text1');
        firstName.setText('Mauricio');

        const pdfBytes = await pdfDoc.save();
        
        const blob = new Blob([pdfBytes], {
            type: 'application/pdf'
        });
			
        const url = URL.createObjectURL(blob);
        $scope.c.pdfUrl = $sce.trustAsResourceUrl(url);
        $scope.$apply();
    };

};

Server Script:

(function() {
    /* populate the 'data' object */
    /* e.g., data.table = $sp.getValue('table'); */
    var attach = "2d000b41c3072210aab7d4fc05013130"; // this is the PDF in my instance
    var gr = new GlideRecord("sys_attachment");
    if (gr.get(attach)) {
        var sa = new GlideSysAttachment();
        var binData = sa.getBytes(gr);
        var base64 = GlideStringUtil.base64Encode(binData);
        data.pdfBase64 = base64;
    } else {
        data.pdfBase64 = "";
    }
})();

 

1 ACCEPTED SOLUTION

Mauricio G Raud
Tera Expert

After reviewing the requirement and a lot researching, the solution was to change the approach. 

 

To summarize:

  1. User clicks/opens the Catalog Item.
  2. A on-load script is triggered.
    1. [On-load] Fetch the PDF from the back end.
    2. [On-load] Prefill the PDF with relevant data using a third party library (like PDF-lib).
    3. [On-load] Trigger a download in another tab with this prefilled PDF.
  3.  Now the Catalog Item has instructions about this PDF and its download.
  4. User fills all required information in the downloaded PDF and saves it in his/her PC.
  5. User attaches the PDF to the Catalog Item and Submits.

View solution in original post

4 REPLIES 4

RixelB
Giga Contributor

You uploaded some gifs. ServiceNow is unable to render them show they are not visible to us. Please paste screenshots instead.

I added some screenshots and also attached them, they are the record producer with the custom widget displaying an iframe with the PDF, and the PDF populated in the record producer.

Ankur Bawiskar
Tera Patron
Tera Patron

@Mauricio G Raud 

This is heavy customization and relies on external library.

I will push back on this requirement.

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
✨ Certified Technical Architect  ||  ✨ 9x ServiceNow MVP  ||  ✨ ServiceNow Community Leader

Mauricio G Raud
Tera Expert

After reviewing the requirement and a lot researching, the solution was to change the approach. 

 

To summarize:

  1. User clicks/opens the Catalog Item.
  2. A on-load script is triggered.
    1. [On-load] Fetch the PDF from the back end.
    2. [On-load] Prefill the PDF with relevant data using a third party library (like PDF-lib).
    3. [On-load] Trigger a download in another tab with this prefilled PDF.
  3.  Now the Catalog Item has instructions about this PDF and its download.
  4. User fills all required information in the downloaded PDF and saves it in his/her PC.
  5. User attaches the PDF to the Catalog Item and Submits.