How to Copy a Dom Node with Event Listeners

How to copy a DOM node with event listeners?

cloneNode() does not copy event listeners. In fact, there's no way of getting hold of event listeners via the DOM once they've been attached, so your options are:

  • Add all the event listeners manually to your cloned node
  • Refactor your code to use event delegation so that all event handlers are attached to a node that contains both the original and the clone
  • Use a wrapper function around Node.addEventListener() to keep track of listeners added to each node. This is how jQuery's clone() method is able to copy a node with its event listeners, for example.

How to copy an event listener in plain Javascript

You can't copy event listeners, but it seems because of the structure of your HTML it's more likely that you shouldn't need to re-add it. Instead of editing the HTML and removing the event listener by doing so, the best bet would be to edit around it.

If you want to remove the text nodes you can iterate through childNodes and separate out what should be removed.

Then to rebuild the appropriate text where you want it you can use insertAdjacentText

if (document.querySelector(".affirm-modal-trigger")) {  const learnMore = document.querySelector("#learn-more");  const modalTrigger = document.querySelector(".affirm-modal-trigger");  const children = Array.from(learnMore.childNodes);
children.forEach(child => { if (child.nodeType === Node.TEXT_NODE || child.matches(".affirm-ala-price")) { if (learnMore.contains(child)) { learnMore.removeChild(child); } } });
learnMore.insertAdjacentText("afterBegin", "Easy Financing With "); modalTrigger.insertAdjacentText("beforeBegin", " ");} else { setTimeout(function() { replaceAffirm(); }, 250);}
<p id="learn-more" class="affirm-as-low-as" data-amount="20000" data-affirm-color="white" data-learnmore-show="true" data-page-type="product">  Starting at  <span class="affirm-ala-price">$68</span> /mo with  <span class="__affirm-logo __affirm-logo-white __ligature__affirm_full_logo__ __processed">Affirm</span>.  <a class="affirm-modal-trigger" aria-label="Prequalify Now (opens in modal)" href="javascript:void(0)">Prequalify now</a></p>

How to find event listeners on a DOM node in JavaScript or in debugging?

If you just need to inspect what's happening on a page, you might try the Visual Event bookmarklet.

Update: Visual Event 2 available.

Adding event listeners to elements cloned from the template tag

Until you 'activate' template using document.importNode, its content are inert nodes which are not part of DOM.

As per addEventListener docs:

The event target may be an Element in a document, the Document itself,
a Window, or any other object that supports events (such as
XMLHttpRequest).

Therefore adding event listeners in your example won't work until you clone template contents and add them to an existing node in document.

If you are ready to use jQuery, there is a workaround. You can use event delegation using jquery on method to bind events to parent element.

something like this:

$(this.container).on('click', '[data-price]', action);

What this will essentially do that any click which is being triggered from children of this.container will bubble up till parent. If it satisfies the selector criteria of [data-price] action will triggered on it.

Access/Copy/Clone an Element’s Event Listeners (or Edit the lineNumber and sourceName)

I wrote the small working test.

Crome extension inject script:

var myScriptElement = document.createElement('script'); 
myScriptElement.innerHTML =
'b=document.getElementById("button");' +
'c=b.cloneNode(true);' +
'b.parentElement.appendChild(c);' +
'c.addEventListener("click", function(e){foo("from new button")}, false);';
document.querySelector('head').appendChild(myScriptElement);

test html:

<html>
<script type='text/javascript' src='test.js'></script>
<body>
<button id='button'>test</button>
<script>
document.getElementById('button').addEventListener('click', function (event) {
foo('from page');
}, false);
</script>
</body>
</html>

and test.js:

function foo(text) {
console.log(text);
};

How do I copy an element's events with its innerHTML?

Unless you are using jQuery you will not be able to clone a node with all it's event handlers and even if you could it's usually not a good idea (I could expand if you need to).

I suppose that these listeners were attached through some processes targetting these DOM nodes (e.g. applying a plugin). What you should be doing is simply do a deep or shallow copy of the DOM elements you want using Element.prototype.cloneNode and re-execute those processes against the clones.

If the cloning process is complex you might consider encapsulating it within the class which is adding the listeners. Something like:

function SomeObj(el) {
this.el = el;
attachSomeHandlersToEl();
}

SomeObj.prototype.clone = function () {
var newEl = this.el.cloneNode(true);

return new this.constructor(newEl);
};

var el = document.getElementById('some-el'),
someObj = new SomeObj(el),
clonedEl = someObj.clone().el;


Related Topics



Leave a reply



Submit