4

I'm working on a project where I have a table full of first names, last names, and e-mail addresses. The last td should be a button that allows the user to copy that particular person's e-mail address to the clipboard.

Also yes, I'm aware this is in old-school JS, I'm working on a legacy project.

Here's my code on codepen.io: https://codepen.io/anfperez/pen/ZZdwWL

HTML

<table style="width:100%">
  <tr>
    <th>Firstname</th>
    <th>Lastname</th> 
    <th>E-mail</th>
    <th>Button</th>
  </tr>
  <tr>
    <td>Jill</td>
    <td>Smith</td> 
    <td id="email">jsmith@whatever.com</td>
    <td><button>Click to Copy</button></td>
  </tr>
  <tr>
    <td>Eve</td>
    <td>Jackson</td> 
    <td id="email">ejackson@whatever.com</td>
    <td><button>Click to Copy</button></td>
  </tr>
</table>

JS

function copyToClipboard() {
    var copyText = document.getElementById("email")
    copyText.select();
    document.execCommand("copy");
    alert("Copied the text: " + copyText.value);
}

So, I have two dilemmas: 1) how can I get each button generated to copy the correct e-mail address (not just one or all of them)? I need to assign unique IDs to each entry it seems, but I don't really know how to start generating those if the list gets longer.

2) I keep getting the error that "copyText.select() is not a valid function". I've been following several tutorials in which this method is used, so I'm not sure why it's not working here.

Leia_Organa
  • 1,894
  • 7
  • 28
  • 48
  • the first step would be to not use the same id multiple times in the document – Robin Zigmond May 02 '19 at 07:42
  • try https://developer.mozilla.org/en-US/docs/Web/API/Range/selectNode – Vadim Hulevich May 02 '19 at 07:44
  • @RobinZigmond that's the other issue I have, I need to get unique IDs to generate so I can target each element separately. – Leia_Organa May 02 '19 at 07:46
  • 1
    @Leia_Organa you don't need ID to get element. – apple apple May 02 '19 at 07:48
  • Im guessing the reason your getting a error when calling .select() is because its not a input field, I dont think you can select the content of a td tag. Maybe you could make it a – Martin M May 02 '19 at 07:48
  • 1
    you shouldn't need unique ids. If you make the `email` id into a class instead, you should be able to select it uniquely based on it being a sibling of the button clicked. (Get the nearest ancestor of the clicked button and then find its descendant with the class `email`) – Robin Zigmond May 02 '19 at 07:48

2 Answers2

6

As Robin Zigmond says, you need to change id="email" to class="email" to be able to find the correct TD, and because each id must be unique.

Once you have done that, you can add an event listener to each button programmatically, and within the listener find the email TD with the email classname.

Selecting text only works in elements that can have text input (i.e. textarea and input type="text"), so you need to create a temporary element to put the text into, and copy it from there.

(function()
{
  let buttons = document.getElementsByTagName('Button');
  for(let i = 0; i < buttons.length; i++)
  {
    let button = buttons[i];
    button.addEventListener('click', e =>
    {
      let button = e.target;
      let email = button.parentNode.parentNode.getElementsByClassName('email')[0].innerHTML;
      let text = document.createElement('input');
      text.setAttribute('type', 'text');
      text.value = email;
      document.body.appendChild(text);
      text.select();
      document.execCommand('copy');
      document.body.removeChild(text);
    });
  }
})();
<table style="width:100%">
  <tr>
    <th>Firstname</th>
    <th>Lastname</th> 
    <th>E-mail</th>
    <th>Button</th>
  </tr>
  <tr>
    <td>Jill</td>
    <td>Smith</td> 
    <td class="email">jsmith@whatever.com</td>
    <td><button>Click to Copy</button></td>
  </tr>
  <tr>
    <td>Eve</td>
    <td>Jackson</td> 
    <td class="email">ejackson@whatever.com</td>
    <td><button>Click to Copy</button></td>
  </tr>
</table>
Matt Ellen
  • 11,268
  • 4
  • 68
  • 90
6

I have modified your Codepen code.

Here is a working example.

document.querySelectorAll('button[data-type="copy"]')
  .forEach(function(button){
      button.addEventListener('click', function(){
      let email = this.parentNode.parentNode
        .querySelector('td[data-type="email"]')
        .innerText;
      
      let tmp = document.createElement('textarea');
          tmp.value = email;
          tmp.setAttribute('readonly', '');
          tmp.style.position = 'absolute';
          tmp.style.left = '-9999px';
          document.body.appendChild(tmp);
          tmp.select();
          document.execCommand('copy');
          document.body.removeChild(tmp);
          console.log(`${email} copied.`);
    });
});
<table style="width:100%">
  <tr>
    <th>Firstname</th>
    <th>Lastname</th> 
    <th>E-mail</th>
    <th>Button</th>
  </tr>
  <tr>
    <td>Jill</td>
    <td>Smith</td> 
    <td data-type="email">jsmith@whatever.com</td>
    <td><button data-type="copy">Click to Copy</button></td>
  </tr>
  <tr>
    <td>Eve</td>
    <td>Jackson</td> 
    <td data-type="email">ejackson@whatever.com</td>
    <td><button data-type="copy">Click to Copy</button></td>
  </tr>
  <tr>
    <td>Eve1</td>
    <td>Jackso1n</td> 
    <td data-type="email">ejackssdfon@whafdstever.com</td>
    <td><button data-type="copy">Click to Copy</button></td>
  </tr>
  <tr>
    <td>Eve2</td>
    <td>Jackson2</td> 
    <td data-type="email">asdas@whasdftever.com</td>
    <td><button data-type="copy">Click to Copy</button></td>
  </tr>
</table>

This source can be helpful as well source

n1md7
  • 2,854
  • 1
  • 12
  • 27