Tag Archives: html5

Capturing a signature in a CRM form using html5


“I have a touchscreen.  I want to capture a signature in a Dynamics CRM form.  If the signature hasn’t been saved, then I want to allow a user to provide their signature.  The next time the record is loaded, after the signature has been saved, I want to load an imagine of the signature to prevent ‘resigning’.”

This is a relatively simple thing with Dynamics CRM thanks to web resources and Xrm.Page.  The general concept is to embed an html web resource in the form that captures the signature using the html5 canvas (preferably using an existing control vs. low level canvas programming).  Before saving, you want to copy the data from the canvas control into a Multiple Lines of Text type hidden field on the form so the data is stored when the record is saved.  Finally, when the web resource is loaded, you want to check if the field has data in it.  If so, you can assume a signature was previously recorded and just show the data as an image. 

Here’s the entire source code for a basic implementation:

1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title>Signature</title> 5 <script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.min.js"></script> 6 <script src="scripts/jSignature.min.js"></script><!-- download from http://willowsystems.github.io/jSignature/#/about/ --> 7 </head> 8 <body> 9 <img id="sigImage" alt="This is an image of the persons signature." style="display:none"/> 10 <div id="sigPanel" style="display:none"> 11 <div id="signature"></div> 12 <button id="clear">Clear</button> 13 </div> 14 <script type="text/javascript"> 15 $(function () { 16 var sigImage = $("#sigImage"); 17 var sigPanel = $("#sigPanel"); 18 var sig = $("#signature"); 19 20 var Xrm = window.parent.Xrm; 21 var sigBase64Attribute = Xrm.Page.getAttribute("msftpoc_esigbase64"); //replace this with your hidden "multiple lines of text" field with a max length of 1,048,576 22 var sigBase64Value = sigBase64Attribute.getValue(); 23 24 sig.bind("change", function (e) { 25 sigBase64Attribute.setValue(sig.jSignature("getData")); 26 }); 27 28 29 if (sigBase64Value != null) { 30 sigImage.css("display", "inline"); 31 sigImage.attr("src", sigBase64Value); 32 } else { 33 sigPanel.css("display", "inline"); 34 sig.jSignature(); 35 $("#clear").click(function() { 36 sig.jSignature("clear"); 37 }); 38 } 39 }); 40 </script> 41 </body> 42 </html> 43

All you have to do is add this web resource to your form (make sure you read instructions in the comments) and update the code to reference your field name.  A few things to note:

  • There are many controls out there, but I chose http://willowsystems.github.io/jSignature/#/about/.  It met all my requirements.  Feel free to use another.
  • The hidden field on the form for my entity is called msftpoc_esigbase64 and uses the Multiple Lines of Text type of Dynamics CRM.  Make sure to change the code to match your field name.
  • For simplicity, I chose to use the default data format of the jSignature control which is a base64 encoded string (hence my field name).  Since base64 encoded strings can be big, I set the max length field to 1,048,576 which is the largest Dynamics CRM allows.  The jSignature control supports other formats.  You could clearly improve on performance of this sample by using one of the smaller string formats.
  • My code doesn’t handle save/autosave side effects.  I simply copy the signature date to the hidden field using the change event of the jSignature control.   A more robust implementation would perhaps wire up to Xrm.Page.data.entity.addOnSave() and intelligently determine whether to copy the data into the field based on save state.  You might also want to consider switching to the image after as successful OnSave with signature if that makes the most sense for your requirements.  I’ll leave that up to you as an exercise for improvement.

Here are a couple screenshots for a quick visualization.

Before Save (signature capable canvas with clear button):


After Save (fixed image of signature):



Cross domain calls from JavaScript

It’s exciting times for web developers.  Many of the hoops we used to have to jump through are being eliminated as more browsers support more of the HTML5 spec and more people are using modern browsers.  One of the things that has me excited is Cross-origin resource sharing (CORS)

In the context of Dynamics CRM, it means that more can be done from HTML and JavaScript web resources without having to do things like proxy calls through a server.  It also reduces the scenarios that require you to implement Cross domain calls to the parent CRM 2011 form.  The need to replace window.parent with window.postMessage when you truly do need to communicate cross domain across iFrames.  However, I’ve used the window.postMessage approach to have a hidden iFrame in a CRM form that is a blank ASP.NET page that calls a third party web service from server-side code, then passes the response to a the client, which then passes the results to the CRM form using window.postMessage and the form code prefills controls in the form.  All this hoop jumping is necessary because of the way older browsers work.  The complexity could be reduced with CORS. 

The rub is that there are still browsers out there that don’t support CORS.  The wikipedia link covers which.  The good news is that modern browser adoption is growing fast.  We’re approaching a time where there is a small enough group of the older browsers where you might feel comfortable displaying a message to your users saying “Are those cobwebs I see on your browser?  Please upgrade to use this app.”  Not everyone can do that, but if you can, then read on.

IE10 supports CORS through the XMLHttpRequest object.  IE8 & 9 support it, but the through the XDomainRequest object.  I don’t know about you, but I don’t XMLHttpRequest directly anyway.  I typically use the jQuery $.get(), $.getJSON(), or $.ajax() methods.  There is a helper library for jQuery called jQuery.iecors that allows you to use jQuery unchanged.  The last thing you need to know is that the server you are calling to has to allow CORS.  Thanks to enable-cors.org, you have a handy reference to know how enable it on your server.