cancel
Showing results for 
Search instead for 
Did you mean: 

SAPUI5 Signature Pad in 2024 - External libs, custom control

rporpino-netzsch
Explorer
0 Kudos
766

Hi everyone,

I am trying to add a Signature Pad in an UI5 app, with the most recent UI5 version and SAP BAS. It's almost 2024 and all Signature Pad posts in the community (SAP, github, stackoverflow, etc) seem to be outdated -- I have tried everything I could find and had no success. There is no native control in UI5 for this yet, right? So it seems to me the ideal would be to implement https://github.com/szimek/signature_pad

I tried also to understand the concepts of custom control, JS Views, how to work with external libraries, etc. So my question is: how can we make a clean/modern implementation of the signature pad? Whether or not to use: NPM installation, custom controls, JS / XML view.

I arrived at a point where I can show the pad in the XML view, but not draw on it. The solution I am trying is based mainly on 3 parts: "signature_pad.js" downloaded from the github repo above, the custom control and the view below. I understood is not a good practice to change "index.html", right? So here are the code samples:

View in /<project>/view/Signview2.view.xml

<mvc:View 
xmlns:mvc="sap.ui.core.mvc"
xmlns:wt="signtest2.control"
xmlns="sap.m" 
controllerName="signtest2.controller.Signview2" 
displayBlock="true">
    <Page id="page" title="{i18n>title}">
        <content> 
        <wt:mySignApp
           id="mySignApp"
           width="800px"
           height="400px"
           thickness="20"/>
        </content>
    </Page>
</mvc:View><br>

Custom control in /<project>/control/mySignApp.js

sap.ui.define(
  ["sap/ui/core/Control", "signtest2/libs/signature_pad"],
  (Control, SignaturePad) => {
    "use strict";

    return Control.extend("signtest2.control.mySignApp", {
      metadata: {
        properties: {
          width: { type: "sap.ui.core.CSSSize", defaultValue: "300px" },
          height: { type: "sap.ui.core.CSSSize", defaultValue: "100px" },
          thickness: { type: "int", defaultValue: 2 },
          bgcolor: { type: "sap.ui.core.CSSColor", defaultValue: "white" },
          signcolor: { type: "sap.ui.core.CSSColor", defaultValue: "black" },
        },
      },

      init() {},

      renderer(oRm, oControl) {
        var thickness = parseInt(oControl.getProperty("thickness"), 10);
        oRm.write("<div");
        oRm.writeControlData(oControl); // writes the Control ID and enables event handling - important!
        oRm.addStyle("width", oControl.getProperty("width")); // write the Control property size; the Control has validated it to be a CSS size
        oRm.addStyle("height", oControl.getProperty("height"));
        oRm.addStyle("background-color", oControl.getProperty("bgcolor"));
        oRm.writeStyles();
        //oRm.addClass("rpb");        // add a CSS class for styles common to all control instances
        oRm.writeClasses(); // this call writes the above class plus enables support for Square.addStyleClass(...)
        oRm.write(">");
        //TODO Write a canvas
        oRm.write(
          "<canvas width='" +
            oControl.getProperty("width") +
            "' " +
            "height='" +
            oControl.getProperty("height") +
            "'"
        );
        oRm.writeControlData(oControl); // writes the Control ID and enables event handling - important!
        oRm.addStyle("width", oControl.getProperty("width")); // write the Control property size; the Control has validated it to be a CSS size
        oRm.addStyle("height", oControl.getProperty("height"));
        oRm.writeStyles();
        oRm.write("></canvas>");
        oRm.write("</div>");
      },
      onAfterRendering: function () {
        var canvas = document.querySelector("canvas");
        try {
          this.signaturePad = new SignaturePad(canvas, {
            backgroundColor: "rgb(255, 255, 255)",
          });
        } catch (e) {
          console.error(e);
        }
      },
      clear: function () {
        this.signaturePad.clear();
      },
      save: function () {
        return this.signaturePad.toDataURL();
      },
    });
  }
);
Currently the error I get with this code is:mySignApp.js:53 TypeError: SignaturePad is not a constructor
Any ideas / working solutions you could share?
Thanks a lot in advance.

Accepted Solutions (0)

Answers (1)

Answers (1)

WouterLemaire
Active Contributor
0 Kudos

Hi,

Your approach looks quite good, putting it in a separate library would make it better but first let's try to make it work.

When you load external libraries using require, you need to give them a different name then the one you have to use in your code. Call it like here "SignaturePadWhatever":

sap.ui.define(
  ["sap/ui/core/Control", "signtest2/libs/signature_pad"],
  (Control, SignaturePadWhatever) => {
    "use strict";

That should do the trick.

 

eg.: here I define it as "pdf" but in in the code I use the name of the library PDFJS:

define: https://github.com/lemaiwo/UI5LabLibraryPDFViewer/blob/1cc5a16392a9151292e320a41b2a8c463d9bc3f2/src/...

PDFJS: https://github.com/lemaiwo/UI5LabLibraryPDFViewer/blob/1cc5a16392a9151292e320a41b2a8c463d9bc3f2/src/...

 

Nowadays, you can also use the ui5-tooling-modules which allows you to just refer to other npm packages (which you have installed as a dependency) and will be automatically resolved by this ui5 tooling plugin. See more details in the Blog post of Peter Muessig: https://community.sap.com/t5/technology-blogs-by-sap/using-npm-packages-in-ui5-without-shims/ba-p/13... 

 

One more tip, you have to use the ui5 renderer v2: https://ui5.sap.com/#/api/sap.ui.core.RenderManager

Or try using Web Components 🙂