E-Signature (Sign Pad) in ServiceNow Catalog Item

TejasSN_LogicX
Tera Contributor

 Hi Everyone,

I recently worked on a ServiceNow project in the healthcare domain, where I came across a challenging requirement.
The client wanted users to acknowledge their requests by signing (E-Signature) while submitting a Catalog item.

Steps:

  • Design the custom widget for the signature pad.
  •  HTML: used <canvas> tag to capture the user’s signature
  •  Client Script: handled signature drawing, clearing, and converting the image to Base64 format.

widget html :

<div class="text-center">
  <canvas id="signature-pad" width="400" height="200"
          style="border:1px solid #ccc; border-radius:8px; cursor:crosshair; touch-action:none;"></canvas>

  <div class="mt-3">
    <button class="btn btn-primary" ng-click="c.clearSignature()">Clear</button>
    <button class="btn btn-success" ng-click="c.attachSignature()">Attach Signature</button>
  </div>
</div>

widget Client script:

api.controller = function($scope) {
    var c = this;
    var canvas, ctx;
    var drawing = false;
    var lastPos = { x: 0, y: 0 };

    c.$onInit = function() {
        setTimeout(function() {
            canvas = document.getElementById('signature-pad');
            if (!canvas) return;

            ctx = canvas.getContext('2d');
            ctx.lineWidth = 2;
            ctx.strokeStyle = '#000';

            canvas.addEventListener('mousedown', startDraw);
            canvas.addEventListener('mousemove', draw);
            canvas.addEventListener('mouseup', endDraw);

            canvas.addEventListener('touchstart', startDraw);
            canvas.addEventListener('touchmove', draw);
            canvas.addEventListener('touchend', endDraw);
        }, 200);
    };

    function getPosition(event) {
        var rect = canvas.getBoundingClientRect();
        if (event.touches && event.touches[0]) {
            return {
                x: event.touches[0].clientX - rect.left,
                y: event.touches[0].clientY - rect.top
            };
        }
        return {
            x: event.clientX - rect.left,
            y: event.clientY - rect.top
        };
    }

    function startDraw(e) {
        drawing = true;
        lastPos = getPosition(e);
    }

    function draw(e) {
        if (!drawing) return;
        e.preventDefault();
        var pos = getPosition(e);
        ctx.beginPath();
        ctx.moveTo(lastPos.x, lastPos.y);
        ctx.lineTo(pos.x, pos.y);
        ctx.stroke();
        lastPos = pos;
    }

    function endDraw() {
        drawing = false;
    }

    c.clearSignature = function() {
        if (ctx) ctx.clearRect(0, 0, canvas.width, canvas.height);
        drawing = false;
        $scope.page.g_form.setValue('signature_data', '');
    };

    c.attachSignature = function() {
        if (!ctx) return alert("Canvas not initialized.");
        var data = canvas.toDataURL('image/png');
        $scope.page.g_form.setValue('signature_data', data);
        alert("Signature captured successfully. It will be attached after submission.");
    };
};

 

2) Created a custom variable in the Catalog item and called the custom widget inside it.

TejasSN_LogicX_0-1767249399036.png

 

3) For the same Catalog item, created a Multi-line Text variable to store the signature image in Base64 format. This variable is just for storing the signature as base64

 

Backend Logic:

  • Created a Flow for the Service Catalog item
  • Added a Custom Action inside the flow
  • Passed the RITM sys_id and the Base64 signature image to the action
  • Attached the generated signature image to the RITM record so it appears under Attachments and Activity

 

Flow custom action:

TejasSN_LogicX_1-1767249421830.png

custom action script:

 (function execute(inputs, outputs) {
    var signatureData = inputs.signature_data;
    //gs.info("tejas_test"+signatureData);

    if (!signatureData)
        return;
    var base64Data = signatureData.replace(/^data&colon;image\/png;base64,/, "");
   // var base64Data = signatureData.replace(/^data&colon;image\/png;base64,/, "");
    var decodedBytes = GlideStringUtil.base64DecodeAsBytes(base64Data);
    var gr = new GlideRecord('sc_req_item');
    gr.addQuery('sys_id', inputs.record_id);
    gr.query();
    if (gr.next()) {
        new GlideSysAttachment().write(
            gr,
            "signature.png",
            "image/png",
            decodedBytes
        );
    }
 
})(inputs, outputs);

 

I have attached the update set : import this update set in your instance

Catalogue item name: User Acknowledgement Request

 

output:

TejasSN_LogicX_2-1767249533425.pngTejasSN_LogicX_3-1767249544017.png

 

 

 

0 REPLIES 0