Home > Software design >  Copy button for html table. Different results with firefox and Chrome. How can I make it similar
Copy button for html table. Different results with firefox and Chrome. How can I make it similar

Time:06-11

I want to copy the second row of an html table to paste it in an excel file. My code works perfectly with firefox, I can paste it in excel and one table cell matches one excel cell. However, when using chrome, when I paste the code in excel, the cells don't match and only the html inside the table cells are retained. I am using vue, here is a link to an example: https://playcode.io/910728

It does work properly when the ref is written in the element, but then I have the heading inside the copied values, which I don't want.

and here is my code:

<script setup>
import {ref} from 'vue'
let matable = [
{ "name": "Link pic", "id": 34, "champ": "<p> Here is a link: <a href='www.google.com'> Link image</a>  <br><br>" },
{ "name": "Source", "id": 16, "champ": "electricity" }, 
{ "name": "Generator", "id": 15, "champ": "Chaudière" }, 
{ "name": "Canton", "id": 1, "champ": "GE" }, 
{ "name": "City", "id": 2, "champ": "Paris" }, 
{ "name": "Numéro de rue", "id": 3, "champ": "72" }, 
{ "name": "Nom de rue", "id": 4, "champ": "Rue du Président" }, 
{ "name": "Surface facades", "id": 36, "champ": 2175.42 },
 ]

const elTable = ref(null)
defineExpose({ elTable });
function selectElementContents(){

let range, sel;

// Ensure that range and selection are supported by the browsers
if (document.createRange && window.getSelection) {

range = document.createRange();
sel = window.getSelection();
// unselect any element in the page
sel.removeAllRanges();

try {
range.selectNodeContents(elTable.value);
sel.addRange(range);
} catch (e) {
range.selectNode(elTable.value);
sel.addRange(range);
}

document.execCommand('copy');


}
}


</script>

<template>
<h1>Hello Vue 3</h1>
<table ref="elTable">
    <thead>
            <th
            v-for="ma in matable"
            :key="ma.id">
            {{ ma.name}}
            </th>
    </thead>
    <tbody >
        <tr >
            <td v-for="ma in matable"
            :key="ma.id"
            v-html="ma.champ"
            >
            </td>
        </tr>
    </tbody>
  </table>
  <input type="button" value="Copier"  ref="copy" v-on:click="selectElementContents">

</template>
<style scoped>

</style>

I also tried to build a specific function for chrome with the clipboard api, but with no luck so far. I does copy, but it doesn't keep the same cell layout like the firefox version. Here is the try out:

function testCopy(){
  let table = matable.map(a => a.champ);

  let contentCo = table.join("  "); 
  console.log("voici ma table",contentCo)

    navigator.permissions.query({ name: 'clipboard-write' }).then(result => {
        if (result.state === 'granted') {
            var blob = new Blob([contentCo], {type: 'text/html'});
            var item = new ClipboardItem({'text/html': blob});
            navigator.clipboard.write([item]).then(function() {
              console.log("Copied to clipboard successfully!");
            }, function(error) {
              console.error("unable to write to clipboard. Error:");
              console.log(error);
            });
        } else {
            console.log("clipboard-permission not granted: "   result);
        }
    })

CodePudding user response:

I might have a workaround. It's not perfect but it works.

The idea is to add a second table under the first one with the ref at the root of the table, then make it hidden with css.

<script setup>
import {ref} from 'vue'
let matable = [
{ "name": "Link pic", "id": 34, "champ": "<p> Here is a link: <a href='www.google.com'> Link image</a> <br><br>" },
{ "name": "Source", "id": 16, "champ": "electricity" }, 
{ "name": "Generator", "id": 15, "champ": "Chaudière" }, 
{ "name": "Canton", "id": 1, "champ": "GE" }, 
{ "name": "City", "id": 2, "champ": "Paris" }, 
{ "name": "Numéro de rue", "id": 3, "champ": "72" }, 
{ "name": "Nom de rue", "id": 4, "champ": "Rue du Président" }, 
{ "name": "Surface facades", "id": 36, "champ": 2175.42 },
 ]


function log() {
  console.log(msg)
}
 const elTable = ref(null)
defineExpose({ elTable });
function selectElementContents(){
   
  let range, sel;
  
  // Ensure that range and selection are supported by the browsers
  if (document.createRange && window.getSelection) {

  range = document.createRange();
  sel = window.getSelection();
  // unselect any element in the page
  sel.removeAllRanges();

  try {
    range.selectNodeContents(elTable.value);
    sel.addRange(range);
  } catch (e) {
    range.selectNode(elTable.value);
    sel.addRange(range);
  }

  document.execCommand('copy');

}
}


</script>

<template>
  <h1>Hello Vue 3</h1>
    <table>
        <thead>
                <th
                v-for="ma in matable"
                :key="ma.id">
                {{ ma.name}}
                </th>
        </thead>
        <tbody >
            <tr>
                <td v-for="ma in matable"
                :key="ma.id"
                v-html="ma.champ"
                >
                
                </td>
            </tr>
        </tbody>
      </table>
      <table ref="elTable" >
        <tbody >
            <tr >
                <td v-for="ma in matable"
                :key="ma.id"
                v-html="ma.champ"
                >
                
                </td>
            </tr>
        </tbody>

      </table>
      <input type="button" value="Copier"  ref="copy" v-on:click="selectElementContents">
                
</template>
<style scoped>

.visually-hidden {
  position: absolute;
  left:     -10000px;
  top:      auto;
  width:    1px;
  height:   1px;
  overflow: hidden;
}

</style>
  • Related