Reputation: 305
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
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
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
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