DmitryJDM
DmitryJDM

Reputation: 11

Copying information at the click of a button

Script that copies information on button click and then returns the original text loses some of the button's content.

enter image description here

enter image description here

enter image description here

missing icon from Font Avesome. Can this be fixed somehow?

I'm a newbie, I'll be glad for a detailed answer.

html:

<p id="battlenet-id">gameid#26737</p>
<p id="xbox-id">gameid#5423</p>

<li><a href="javascript:void(0);" class="link-st battlenet" onclick="copyToClipboard('battlenet-id', this)"><i class="fab fa-battle-net"></i> Battle.net</a></li>
<li><a href="javascript:void(0);" class="link-st xbox" onclick="copyToClipboard('xbox-id', this);"><i class="fa-brands fa-xbox"></i> Xbox</a></li>

js

function copyToClipboard(elementId, thisButton) {
  let oldText = thisButton.textContent
  thisButton.textContent = '!Copied!'
  const timeout = setTimeout(function() { thisButton.textContent = oldText }, 3000);
  var aux = document.createElement("input");
  aux.setAttribute("value", document.getElementById(elementId).innerHTML);
  document.body.appendChild(aux);
  aux.select();
  document.execCommand("copy");
  console.log("🎉 Copied to clipboard!");
  document.body.removeChild(aux);
}

Upvotes: 1

Views: 64

Answers (2)

ThS
ThS

Reputation: 4783

Only using textContent won't be suffice to keep the icon after copying the text. To have the original content (text + icon) reverted after performing the copy, you'd need to use a combination of textContent and innerHTML attributes.

Here's a demo:

/** select all the buttons that have the copy feature based on the "link-st" class */
const toBeCopiedElements = document.querySelectorAll('.link-st');

/** 
 * loop through those buttons and add a click event listener to each one that perform the copy feature
 */
toBeCopiedElements.forEach(el => el.addEventListener('click', e => {
  /** 
   * el: references the current button in the forEach loop
   * oldHTML: has the initial HTML content of the button 
   * aux: the input element that is used to perform the "copy" command
   */
  const oldHTML = el.innerHTML,
    aux = document.createElement('input');

  /** set the buttons text as the newly created input's value */
  aux.value = el.textContent;

  /** perform the copy command and the cleanups afterwards (the next 4 line) */
  document.body.appendChild(aux);
  aux.select();
  document.execCommand('copy');
  document.body.removeChild(aux);

  /** replace the buttons HTML content with "!Copied!" text. Must use "innerHTML" here in order to fully remove the old text and icon */
  el.innerHTML = '!Copied!';

  /** reset the button's HTML content (using ".innerHTML") to the original content after 3s */
  setTimeout(() => el.innerHTML = oldHTML, 3000);
}));
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>

<!-- Removed the inline event listeners and switched to the modern way of atttaching listeners (using "addEventListener" methodd) -->
<li><a href="javascript:void(0);" class="link-st battlenet"><i class="fab fa-battle-net"></i> Battle.net</a></li>
<li><a href="javascript:void(0);" class="link-st xbox"><i class="fa-brands fa-xbox"></i> Xbox</a></li>

The above demo is definitely not the only way to get things done. There might be some other ways most notably using the modern Clipboard API to have the copy-to-clipboard feature.

Upvotes: 1

Miguel Fern&#225;ndez
Miguel Fern&#225;ndez

Reputation: 45

According to Node.textContent - MDN Docs

Both textContent and innerText remove child nodes when altered

A good option would be using a span tag around the text inside your a, so that the i icon element is not altered when modifying the textContent.

In your case, the resulting HTML code will look like this:

<li><a href="javascript:void(0);" class="link-st xbox" onclick="copyToClipboard('xbox-id', this);"><i class="fa-brands fa-xbox"></i> <span>Xbox</span></a></li>

And I think to copy the whole content of the a tag you need to use innerHTML instead, otherwise you would get only the text.

Or you could just save both i and span elements saving a copy of them independently and append them again after.

Upvotes: 1

Related Questions