"Copy to clipboard" button

Hey Anvillers,

Does anyone know how I could implement a “Copy to clipboard” link in an Anvil app?

I’d like to allow a user to copy the value of a component to the clipboard for them to then paste somewhere else

Thanks!

Yes, you can.

This is very rough and ready just to prove a point, but what I have done in the example attached is :

Create a custom HTML form (Form1) and add this code to the html :

<script>
      function cpy() {
      var t = document.getElementsByClassName("anvil-role-copysource");
      t[0].select();
      document.execCommand("copy");
    }  
  
</script>

Create a blank standard form (Form2) and set this as the default form to display on start up.
Drag Form1 into Form2 (creating a component called self.custom_1).
In form1 create a text box and a button.
Create a Role called “copysource”.
Add that role to the textbox.
Add this code to the button click event :

self.custom_1.call_js("cpy")

Now run the project and type in the text box. Click the button and the text should be in the clipboard.
I have added a second textbox to paste into for testing.

https://anvil.works/ide#clone:IMYBRTOUIRCUORXQ=GIFJYBSYJANDR3N7L7SRLDI4

1 Like

Thanks @david.wylie that’s really useful! :slight_smile:

Can I ask - is there a reason for putting this onto a custom HTML component, and then adding that component to the main form - as opposed to just putting the script onto the main form itself?

Thanks!

That’s just how I did it in one of my projects. I’m sure there are many other ways to lay that out.
As long as the JS function is in scope for the calling form then you should be able to call it ok.

Note my method is not perfect as the JS searches for all elements with that class name then operates on just the first one (element 0). So you need to be careful to not add that role to any other component else it might cause some confusion.

Here’s a version using the JS inside an asset file :

https://anvil.works/ide#clone:IAZHSZY6RUTOUXIQ=VR7BOUTZVNFQ6XWS5ECEB3YY

Things to note here are :

  • cpy() function is now in an asset file “copytext.js”
  • the material theme HTML file (“standard-page.html”) has a “source” tag block loading the asset file
  • you must call_js from the parent file using “get_open_form().call_js()”

Great thanks a lot! :slight_smile:

An alternative that avoids the selection of the text in the control (if that matters in your case) is to pass the text to copy into the Javascript function, which then can become as simple as this:

<script>
function copyText(text) {
  navigator.clipboard.writeText(text)
}
</script>
1 Like

Thanks - I’ll give it a go!

Hi @jshaffstall - getting a ‘navigator.clipboard’ is undefined error when I try to use this. Have tried googling a bit but it just seems to suggest it’s about browser compatibility.

Is there anything else I have to do to enable the functionality that you know of e.g. request a permission or something? Am using the latest version of Firefox…

@mattstibbs According to Can I Use it’s supported in recent versions of Firefox, https://caniuse.com/#feat=clipboard but that doesn’t appear to be true. There do seem to be ways of enabling it if you’re installing an extension, but nothing I could find for web apps.

Looks like document.execCommand(‘copy’) is the way to go for now. A little digging into the Anvil IDE shows that what they select is a hidden field, so you don’t actually see the selection on the visible field.

1 Like

As an update to this, I ended up going with this code:

<script> 
  function copyclip(texttocopy) {
    // Create new element
    var el = document.createElement('textarea');
    // Set value (string to be copied)
    el.value = texttocopy;
    // Set non-editable to avoid focus and move outside of view
    el.setAttribute('readonly', '');
    el.style = {position: 'absolute', left: '-9999px'};
    document.body.appendChild(el);
    // Select text inside element
    el.select();
    // Copy text to clipboard
    document.execCommand('copy');
    // Remove temporary element
    document.body.removeChild(el);
  }
</script>

This creates a temporary hidden element in the DOM to copy from, as opposed to using a permanent element on the page.

This then allows me to pass in a value to be copied, as opposed to having to use a selectable field (e.g. text input) - which means I can copy the value of a label on the page.

def button_1_click(self, **event_args):
  self.call_js("copyclip", self.lbl_odscode.text)

I was building a very quick and dirty search page for the National Health Service Organisational Data Service (ODS) https://ods-search.anvil.app

Thanks for the inspiration both @david.wylie and @jshaffstall!

9 Likes

That’s a lovely approach! Thanks for sharing what you ended up with, I’ll use that in place of my navigator.clipboard usage until navigator.clipboard is more widely supported.

Yes it works nicely - but I should clarify the JavaScript isn’t mine - I just found it after trying out a range of different snippets from the interwebs :grinning:

I just had an opportunity to test this out in one of my apps as well. I eventually got it working, but I did notice a limitation. If my understanding is correct, document.execCommand('copy') only works within the confines of a user command (a button click or similar). Any function call ahead of self.call_js("copyclip", text) will somehow break out of the user command, causing the text to not be copied to the clipboard.

For example, I use it much like Anvil does to copy a URL for the app. Making a string literal or constant of my app’s origin works, whereas calling anvil.server.get_app_origin() right before does not. Similarly, using get_open_form().call_js("copyclip", text) from a subform that doesn’t have its own HTML causes the same issue. Just a note for those who may try to attempt this in the future.

1 Like

Hi everyone - I’m coming to this over 2 years later but can’t find anything else in the forum regarding clipboard. I use the pyperclip module on my desktop all the time… if that can be added to the list of Anvil’s pre-installed packages, will that work inside client code/Forms?

Last I checked, pre-installed packages work only server-side. If you can merge the source of a package into your client-side code – and if it still works that way – then you may have something.

Aha! Thanks for the clarification.

1 Like

Hi @mattstibbs - @hans.melberg has kindly posted a link here from his really helpful summary of custom components: csvShare.app: An app to store and share csv files.

I’m a Javascript ‘virgin’ and I suspect like many people was drawn to Anvil because of it’s “Pure Python” promise. In the absence of an in-built component, I just wondered if you or others would be kind enough to offer the corresponding Javascript code for Pasting from the clipboard please and add it to this thread?

A typical use case would be: user has just copied something to the clipboard (maybe a large section of a spreadsheet) and Anvil client needs to pass this to an Anvil server function for further processing.

Having this code snippet would be hugely helpful for me, and many others to come I’m sure.

Many thanks!

Sometimes I am forced to use some javascript, but I am far from a javascript expert. In general it is possible to use a javascript function in Anvil by, first, incuding the javascript function itself in the HTML or under Assets and, second, calling this function from Python using call_js().

A quick google search indicates that it is possible to use javascript to get the content of the clipboard: https://stackoverflow.com/questions/50633601/is-it-possible-to-paste-from-clipboard-onclick-in-javascript. Except for that, I am afraid I do not know enough to give you a good solution right away, unfortunately.

1 Like

Thanks @hans.melberg. I was hoping someone who understands the code by @mattstibbs above could weigh in… In Python for example there’s a simple ‘sister’ method pyperclip.copy() / pyperclip.paste("text") and I imagined that just changing a line or two in the code code above might do the job, rather than me blindly trusting Javascript I don’t understand from stackoverflow etc if possible!

As with all coding, it’s Voodoo Magic if you don’t know the language, but often rather simple once you do…

Yes, Voodoo and obvious simplicity at once!

Security also dictates that at the very least javascript cannot have access to the clipboard without some user permission/input (If it had it, pages could steal the content of your clipboard without your permission).

2 Likes