Signature Field Options

I’m looking for a way for users to sign a signature field with their finger/mouse and have it saved to the database as an image. I looked around for an API that does this but everything seemed to be related to electronic/digital signatures and not signature images.

I like the look and feel of this signature pad…https://github.com/szimek/signature_pad

…and put it into the forum app with a HTML element as an iFrame…https://bubble.io/page?type=page&name=signaturefield&id=forumapp3&tab=tabs-1

but there doesn’t appear to be anyway to get it into the Bubble database from there. I looked at creating a block in Blockspring but wasn’t sure if it could be done there.

Anyone know of a way to do this or have recommendations on a simple web API that will return and image that can be stored in the Bubble database?

Hi there,

Is this a bit what you’re looking for?

Preview:

Edit page:
https://bubble.io/page?type=page&name=data_image_png_base64_ivb&version=test&id=lenex-test-environment&tab=tabs-1

When you insert a signature, it will call upon the POST API that I created using Javascript, which will enter the string that the HTML outputs into the database. This might still not be idea, but it might be the ‘edge’ or ‘idea’ you need to move on? :slight_smile:

Regards,
Olrik

Thanks Olrik,
Yes, this would probably work fine. I suppose I need to learn some Javascript to tweak it. I have a few questions on how you implemented this.

Looks like you deleted some extraneous lines in the HTML A field and added the below:

function post(path, params, method) {
method = method || "post"; // Set method to post by default if not specified.

// The rest of this code assumes you are not using a library.
// It can be made less wordy if you use one.
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);

for(var key in params) {
    if(params.hasOwnProperty(key)) {
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("type", "hidden");
        hiddenField.setAttribute("name", key);
        hiddenField.setAttribute("value", params[key]);

        form.appendChild(hiddenField);
     }
}

document.body.appendChild(form);
form.submit();

}

and

post('https://lenex-test-environment.bubbleapps.io/version-test/api/1.0/wf/receivesignature', {signature: signaturePad.toDataURL()});

setTimeout(function (){
signaturePad = new SignaturePad(canvas);
}, 50);

It also looks like you created a public API with a private key, but I didn’t see where that private key is located in HTML A window. Is there any other components inside or outside of Bubble that makes this work?

The main change I think I’d need to make with this prototype is to figure out how to suppress the

{
"status": "success",
"response": {}

}

message after the save button is pressed.

Thanks again!

Sorry I haven’t replied before. It’s just that my business just keeps running, and I’m using Bubble to build some stuff on the side, and it isn’t my core business :wink:

To be quite frank with you, I don’t have in-depth knowledge of Javascript myself. I know enough to be dangerous, I always say. I learned how to code in Python and I’m pulling from that knowledge to know what the code does and adjust it. But not enough to really alter it exactly to what I would want.

To answer your questions, Yes. I did throw in some Javascript to create the function “Post”, which I need to send a POST to the Bubble API that I created. The POST method is not something you can call in standard Javascript, so that’s why that first code block is in the HTML field.

The second bit you mention is the actual POST method, that sends the data to the Bubble API. and what it sends is “signaturePad.toDataURL()”, which is the Base64 string of the image of the signature. Since I send that to an API we can put it into a thing and use it inside of Bubble.

And what you said with “The main change I think I’d need to make with this prototype is to figure out how to suppress…” is exactly what I tried with this bit of code:

setTimeout(function (){
signaturePad = new SignaturePad(canvas);
}, 50);

As I try to reset the canvas after save has been pressed. But I didn’t seem to get that to work.

That all being said. After writing the above I did another attempt at making it work, and I think I figured it out :slight_smile:

The code is a LOT messier now, since the HTML A block should NOT be an iFrame. Otherwise this bit of code:

$("button:contains('...edit me...')").click();

can’t ‘virtually click’ the bubble “…edit me…” button. Obviously you can stuff away this button somewhere in a corner. Just make sure it’s “visable” for the HTML. So don’t use the “This element is visible on page load” option to hide it. Or the page won’t know it’s there.

I made the “edit me” button toggle the visibility of the HTML block, but you can obviously make some kind of “popup” appear telling the user that their signature has been saved, or whatever workflow you want to trigger.

This bit of code:

$.ajax({
    url:'https://lenex-test-environment.bubbleapps.io/version-test/api/1.0/wf/receivesignature',
    type:'post',
    data: {signature: signaturePad.toDataURL()}
});

Is the javascript that calls the POST method to send the signature to the Bubble API. In my test app there is an API Key generated, but since everyone can read the Javascript, it wouldn’t be hard to get hold of the key as well. So I suggest you have 1 endpoint that JUSTS handles storing the signature, to make sure you have minimal security risks. Again: I am no expert, I have merely managed to piece some stuff together :slight_smile:

Also make not that I copied the entire SignaturePad Javascript into the HTML A block, as I was having problems loading it in using the <.script> tags. If you can get it to work with the tags, that’d be a lot cleaner :wink:

And last but not least: I added the CSS sheet to the Page header. Edit the page and scroll to the bottom. You will find it there, so that it would be able to load in the header, since the HTML block is no longer an iframed block.

If you have any questions, feel free to shoot me another reply. It’s been fun working this out. I had need of something like this myself, as well. And you gave me the motivation to work something out! :thumbsup:

Disclaimer:
This is most definitely not supported by Bubble. If something breaks they will not be able to help you. :slight_smile:

Credits:
@gurun - Native JS Bridge - two way bridge for Javascript addons in Bubble
Thank you for showing me how to use Javascript to click on Bubble buttons. That definitely made this possible.

Regards,
Olrik

1 Like

Nice work @Lenex!

I came up with an alternative way to integrate with Bubble, then saw yours, haha.
Here’s my method: Signature pad example

Great work @Lenex and thanks for the credits :slight_smile:

The ajax call is awesome but has a higher risk of breaking than @mishav s implementation in my opinion. Take that into concideration.

If you would manage to dig out the nested function that uses the bubble call via their own “service adapter” it would start to open up awesome opportunities. Start by inspecting the loaded JS code. I`ve prettified the code with an external service (http://jsbeautifier.org/) but its highly obfuscated so requires lots of brainpower to unwrap it properly. Would be nice to just use something like: e.anotherfunction.i.post(signatures, signaturePad.toDataURL());

If we could unwrap that we could run workflows etc. in a safer way straight from JS.

@mishav and @Lenex
In regards to performance I find jquery “contains” to not be optimal.

You can add a custom HTML element grouped inside with the button.
<div id="someid"> </div>
and add a script to select the DIV and jump to previous DOM node (the button).
You can use jquery but I urge you to use vanillajs as its immensely faster.

//in Jquery it was:
var el = $("#element");
//alternative
// traditional JS
var el = document.getElementById("element");

// new school JS
var el = document.querySelector("#element");

http://callmenick.com/post/jquery-functions-javascript-equivalents

OR

Regarding the $.ajax() call, if you pass a function to success, it will eat the response in a way you want it to.

https://api.jquery.com/jquery.post/

$.ajax({
  type: "POST",
  url: url,
  data: data,
  success: success,
  dataType: dataType
});

I agree, would be great. It’d be better if it was officially supported though, otherwise it’d be vulnerable to changes in Bubble core code.

Nice research, @gurun. Which code snippets were you looking at optimising?

The jquery contains function should be avoided, especially if you start stacking up these in a single page.

Performance test:

This

if ($('.shipping .price').text() === "FREE"){ 
    $('.shipping .price').addClass('text-primary'); 
}

is much faster than:
$('.shipping .price:contains("FREE")').addClass('text-primary');

That makes sense, the :contains is more expensive because it does more:

https://api.jquery.com/contains-selector/

The matching text can appear directly within the selected element, in any of that element’s descendants, or a combination thereof.

Whereas === does a one-on-one comparison. I agree it makes sense not to use it if it’s not needed.

Nice discussion!

Honestly, I am no programmer. So knowledge of what works best is definitely not my strong suit. Just getting this discussion is nice to follow.

Regards,
Olrik