euvl / v-clipboard

Simple and powerful clipboard plugin for Vue.js 2 and 3
MIT License
522 stars 39 forks source link

Copy not working when triggered inside a Vuetify dialog #18

Closed anzuj closed 1 year ago

anzuj commented 4 years ago

I've played around with this a while now and noticed that this composition works:

<template>
    <div>
       <v-btn v-clipboard="inviteUrl">Copy</v-btn> <!-- works -->
    </div
</template>

data: () => ({
        inviteUrl: "www.fakeurl.com",
    }),

However, when I implement a Vuetify dialog in my template, it no longer works, as in the text www.fakeurl.com does not get copied upon button press. No errors in console either.

<template>
    <v-dialog v-model="linkDialog">
        <template v-slot:activator="{ on, attrs }">
            <v-btn v-bind="attrs" v-on="on">
                Get link
            </v-btn>
        </template>

        <v-card>
            Here's your link: {{ inviteUrl }}

            <v-btn v-clipboard="inviteUrl">Copy</v-btn> <!-- doesn't work -->
        </v-card>
    </v-dialog>
</template>

Any advice on why the copy function won't work when nested in elements inside Vuetify framework elements?

Thanks!

BenShelton commented 3 years ago

This seems to be a general problem with this method of copying. My hunch is that when appending an element to the document.body it's not able to be properly selected when a dialog is open, so the copy fails even though it shows as successful. This is also seen in other libraries, check out https://github.com/Inndy/vue-clipboard2#it-doesnt-work-with-bootstrap-modals

The solution there, which I believe could also be added to this library, is to allow providing an element as an option so you can append the copiable element somewhere within the dialog which will allow it to copy as expected.

uke5tar commented 3 years ago

I was struggling with this issue a few hours until I found this thread: https://github.com/vuetifyjs/vuetify/issues/6892#issuecomment-486438564

What fixed it for me in the end was this method as suggested in the thread above by the user Pazza:

  methods: {
    clipboard (str) {
      const el = document.createElement('textarea');
      el.addEventListener('focusin', e => e.stopPropagation());
      el.value = str;
      document.body.appendChild(el);
      el.select();
      document.execCommand('copy');
      document.body.removeChild(el);
    },
  },

I just turned it into a mixin and removed the plugin from my codebase. One less dependancy so its even better. I tested it only in Chrome and Firefox and there it works. If you need to support older browsers it might make sense to test it there before implementation.

willbrowningme commented 1 year ago

You can also use the Clipboard API since document.execCommand() has been deprecated.

methods: {
  clipboard (str) {
    navigator.clipboard.writeText(str).then(() => {
      // success
    },() => {
      // error
    });
  },
},