jennab
jennab

Reputation: 305

Javascript - Copy to clipboard without concrete Id in HTML tag

On an HTML page, there should be several snippets in code tags. It should be possible to copy the code to the clipboard via a button click. I have working code for one code tag for which the reference is made using an ID. However, how to change the JavaScript code so that the copying is not dependent on a manually predefined ID in the code tag. When hitting the copy to clipboard button for a certain code snippet, it should automatically copy the content of the intended code block - while having many other code tags with the same copy to clipboard button on the page. My example shows one code block with a predefined ID. How to avoid the ID in the JS code to make it work independently?

function copy_text() {
  const str = document.getElementById("copy_code").innerText; const el = document.createElement("textarea");
  el.value = str; el.setAttribute("readonly", ""); el.style.position = "absolute";
  el.style.left = '-9999px'; document.body.appendChild(el);
  el.select(); document.execCommand("copy"); document.body.removeChild(el);
};
<code id="copy_code">some code 1<br>some code 2<br>some code 3</code>
<button onclick="copy_text()">Copy to clipboard</button>

Upvotes: 2

Views: 1615

Answers (3)

Wassim Bala
Wassim Bala

Reputation: 1

function copy_text() {
  const str = document.getElementById("copy_code").innerText; const el = document.createElement("textarea");
  el.value = str; el.setAttribute("readonly", ""); el.style.position = "absolute";
  el.style.left = '-9999px'; document.body.appendChild(el);
  el.select(); document.execCommand("copy"); document.body.removeChild(el);
};
<code id="copy_code">some code 1<br>some code 2<br>some code 3</code>
<button onclick="copy_text()">Copy to clipboard</button>

Upvotes: 0

connexo
connexo

Reputation: 56720

Please note that document.execCommand is being superseded by the clipboard API.

Just pass the id of the element it's supposed to work on to the copy handler. This keeps it independent of the DOM structure and the way that the button and the corresponding code block are placed in the DOM, relative to each other.

function copy_text(id) {
  if (!id) return;
  const code = document.getElementById(id);
  if (!code) return;
  if (navigator && navigator.clipboard) { // need to check because it's only available on https and localohost
    navigator.clipboard.writeText(code.innerHTML);
  }
};
<code id="foo">some code 1<br>some code 2<br>some code 3</code>
<button onclick="copy_text('foo')">Copy to clipboard</button>
<br/>
<code id="bar">some code 3<br>some code 4<br>some code 5</code>
<button onclick="copy_text('bar')">Copy to clipboard</button>
<textarea placeholder="Try to paste here to see if it works"></textarea>

If the DOM structure is fix anyway (the code block always directly being followed by the copy button), you can get rid of the id completely using element.previousElementSibling. In the following example I'm generating the button elements dynamically:

function copy_text(e) {
  const code = e.target.previousElementSibling;
  if (!code) return;
  if (navigator && navigator.clipboard) { // need to check because it's only available on https and localohost
    navigator.clipboard.writeText(code.innerHTML);
  }
}

document.addEventListener('DOMContentLoaded', function() {
  const snippets = document.querySelectorAll('.copyable-snippet');

  for (const snippet of snippets) {
    const button = document.createElement('button');
    button.type = 'button';
    button.textContent = 'Copy to clipboard';
    button.addEventListener('click', copy_text);
    snippet.parentElement.insertBefore(button, snippet.nextSibling);
  }
});
<code class="copyable-snippet">some code 1<br>some code 2<br>some code 3</code>
<code class="copyable-snippet">some code 3<br>some code 4<br>some code 5</code>
<textarea placeholder="Try to paste here to see if it works"></textarea>

Upvotes: 3

Ivan86
Ivan86

Reputation: 5708

You can pass this to the copy_text() method call so your function knows exactly which button triggered the onclick event. You can then get the elements of it's parent container, assuming each code block and it's button are inside inside a parent container:

function copy_text(item) {
  const str = item.parentNode.querySelector('code').innerText;
  const el = document.createElement("textarea");
  el.value = str;
  el.setAttribute("readonly", "");
  el.style.position = "absolute";
  el.style.left = '-9999px';
  document.body.appendChild(el);
  el.select(); document.execCommand("copy");
  document.body.removeChild(el);
};
<div>
  <code>1<br>2<br>3</code>
  <button onclick="copy_text(this)">copy</button>
</div>

<div>
  <code>4<br>5<br>6</code>
  <button onclick="copy_text(this)">copy</button>
</div>

In case if each code block and it's button are not inside some parent container and are entered in HTML exactly like in the question you can use

const str = item.previousElementSibling.innerText;

instead of

const str = item.parentNode.querySelector('code').innerText;

function copy_text(item) {
  const str = item.previousElementSibling.innerText;
  const el = document.createElement("textarea");
  el.value = str;
  el.setAttribute("readonly", "");
  el.style.position = "absolute";
  el.style.left = '-9999px';
  document.body.appendChild(el);
  el.select(); document.execCommand("copy");
  document.body.removeChild(el);
};
<code>1<br>2<br>3</code>
<button onclick="copy_text(this)">copy</button>
<br>
<code>4<br>5<br>6</code>
<button onclick="copy_text(this)">copy</button>

Upvotes: 2

Related Questions