4.4K
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);
6 comments
Signature pad code is not working in MAC
Hello Yesh,
It should work. May i know, issue which you are facing. I will try to resolve that issue.
Thank You,
Dhanik
it doesn’t work in model popup
Hello Manish,
What issue you are facing in model popup?
Thank You,
Dhanik
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.
Hello Narendra,
You can use checkCanvasStatus helper method to validate empty image save.
Thank You,
Dhanik