Home Salesforce Create Signature Pad in Salesforce Lightning

Create Signature Pad in Salesforce Lightning

by Dhanik Lal Sahni

In one of my last project, client wanted to get customer signature with salesforce record to get customer agreement. We have many app exchange product like Adobe Esign, Docu Sign etc.

Let us create similar signature pad in lightning component. We will need signature pad library for this. Download this library from my Github account. Add this library in static resources as signaturePad.

Now create lightning component for signature pad.

SignaturePad.cmp

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId,forceCommunity:availableForAllPageTypes" controller="SignatureController">

<! -- Static Resources -->
<ltng:require scripts="{!$Resource.signaturePad}" afterScriptsLoaded="{!c.doInit}" />

<! -- Method which can be accessed from other component to Save Signature -->
<aura:method name="SaveSignature" action="{!c.saveSignatureOnClick}" description="Save Signature" />

<! -- Method to check that signature is empty yet -->
<aura:method name="IsCanvasEmpty" action="{!c.IsCanvasEmpty}" description="Check Signature is done or not" />

<!-- Id of the Parent record for which this signature pad will be saved -->
<aura:attribute name="recordId" type="Id" />

<aura:attribute name="IsImageDrawn" type="Boolean" default="false" />
<aura:attribute name="signaturePad" type="Object" />

<div class="slds slds-grid slds-wrap">
<div class="slds-size--1-of-1 slds-m-top--small slds-p-right--small">
<lightning:buttonIcon class="" iconName="utility:clear" variant="bare" alternativeText="Clear" iconClass="dark" onclick="{!c.clearSignatureOnClick}"/>
<canvas id="signature-pad" aura:id="signature-pad" class="signature-pad"></canvas>
<canvas id='blank' aura:id="blank" class="signature-pad" style='display:none'></canvas>
</div>
</div>
</aura:component>

SignaturePad Controller JS

({
    doInit : function(component, event, helper) {
        helper.handleInit(component, event);
    },
    saveSignatureOnClick : function(component, event, helper,data){
        helper.handleSaveSignature(component, event,helper,component.get("v.recordId"));
    },
    clearSignatureOnClick : function(component, event, helper){
        helper.clearCanvas(component, event);
    },
    IsCanvasEmpty: function(component, event, helper){
        return helper.checkCanvasStatus(component, event);
    }
})

SigntaurePad Helper JS

({
    handleInit : function(component, event) {
        //
        var canvas = component.find('signature-pad').getElement();
        var ratio = Math.max(window.devicePixelRatio || 1, 1);
        canvas.width = canvas.offsetWidth * ratio;
        canvas.height = canvas.offsetHeight * ratio;
        canvas.getContext("2d").scale(ratio, ratio);
        var signaturePad = new SignaturePad(canvas, {
            minWidth: .25,
            maxWidth: 2
        });
        component.set("v.signaturePad", signaturePad);
    },
    handleSaveSignature : function(component, event,helper,data) {
        var sig = component.get("v.signaturePad");
        if(!sig._isEmpty){
            var action = component.get("c.uploadSignature");
             action.setParams({
                "caseId": data,
                "b64SignData": sig.toDataURL().replace(/^data:image\/(png|jpg);base64,/, "")
            });
            action.setCallback(this, function(response) {
                var state = response.getState();
                if (component.isValid() && state === "SUCCESS") {
                    this.clearCanvas(component, event);
                    var errorReturned = response.getReturnValue();
                    
                    if(errorReturned == ''){
                        //this.showToast(component,true, '');
                        console.log("Signature Attached");
                    } else {
                        console.log(errorReturned); // Technical error for maintenance
                        //this.showToast(component,false, $A.get("$Label.c.Signature_Error_Report_Already_Submitted"));
                    }
                }
            });
            $A.enqueueAction(action);
        }
    },
    clearCanvas : function(component, event) {
        var sig = component.get("v.signaturePad");
        sig.clear();
    },
    checkCanvasStatus : function(component, event) {
       
        var data=component.get("v.signaturePad"); 
       
        return data._isEmpty;
    },
    
    //Toast Message to show 
    showToast: function(component,isSuccess, error){
        var toastEvent = $A.get("e.force:showToast");
        var type = isSuccess ? "success" : "error";
        var title = isSuccess ? $A.get("$Label.c.Signature_Toast_Title_Success") : $A.get("$Label.c.Signature_Toast_Title_Error");
        var message = isSuccess ? $A.get("$Label.c.Signature_Toast_Text_Success") : error;
        toastEvent.setParams({
            "type": type,
            "title": title,
            "message": message,
            "mode": "pester"
        });
        toastEvent.fire();
    }
    
})

Apex to save signature as attachment

@AuraEnabled
    public static String uploadSignature(String caseId, String b64SignData){
        try {
            Attachment n = new Attachment();
            //You will want to tie your attachment to some type of custom or standard object
            n.ParentId = caseId;
            n.Name = 'Signature_'+String.valueOf(Date.today()).substring(0,10);
            n.Body =  EncodingUtil.base64Decode(b64SignData); 
            system.debug('Body' + n.Body);
            //If we were saving a PDF as an attachment the ContentType would be 'pdf'
            n.contentType = 'image/jpeg';
            insert n;
            return '';
        }
        catch (Exception e)
        {
            String errorMessage = e.getMessage();
            Integer occurence;
            if (e.getMessage().contains('FIELD_CUSTOM_VALIDATION_EXCEPTION')){
                occurence = errorMessage.indexOf('FIELD_CUSTOM_VALIDATION_EXCEPTION,') + 34;
                errorMessage = errorMessage.mid(occurence, errorMessage.length());
                occurence = errorMessage.lastIndexOf(':');
                errorMessage = errorMessage.mid(0, occurence);
            }
            system.debug('Error: '+e);
            system.debug('Error: '+errorMessage);
            
            return errorMessage;
        }
    }

Use SignaturePad in other component

<aura:attribute name="CaseId" type="String" default=""/>

<c:SignaturePad aura:id="SignaturePad1"></c:SignaturePad>

Calling SaveSignature Method to save signature as attachment

var childComponent = component.find("SignaturePad1");
childComponent.set("v.recordId",component.get("v.CaseId"));
childComponent.SaveSignature(component, event, helper);

 

You may also like

6 comments

Yesh May 25, 2023 - 10:58 am

Signature pad code is not working in MAC

Reply
Dhanik Lal Sahni May 27, 2023 - 10:18 am

Hello Yesh,

It should work. May i know, issue which you are facing. I will try to resolve that issue.

Thank You,
Dhanik

Reply
manish November 15, 2023 - 9:41 am

it doesn’t work in model popup

Reply
Dhanik Lal Sahni November 15, 2023 - 3:01 pm

Hello Manish,
What issue you are facing in model popup?

Thank You,
Dhanik

Reply
Narendra May 11, 2024 - 10:25 am

Hi DHANIK,

Everything is working fine, but i am facing one major issue. When just placing cursor inside signature box without making any signature it is saving empty attachment. In my scenario signature is required, i am not getting validation alert for signature. Can you please help me.

Reply
Dhanik Lal Sahni May 14, 2024 - 7:50 am

Hello Narendra,
You can use checkCanvasStatus helper method to validate empty image save.

Thank You,
Dhanik

Reply

Leave a Comment