Manipulating Innerhtml Removes the Event Handler of a Child Element

Manipulating innerHTML removes the event handler of a child element?

Yes, when you do:

document.body.innerHTML += '<br>'; 

You're really doing:

document.body.innerHTML = (document.body.innerHTML + '<br>'); 

So you're completely destroying and recreating all the content.

Element innerHTML getting rid of event listeners

It seems you misunderstood the problem. The problem is that you are overwriting innerHTML in order to insert contents.

Never use innerHTML to insert contents. It will remove all the internal data, like event listeners. This is what happens here.

If you want to prepend some HTML string, use insertAdjacentHTML:

var count = 0;function createOnclickFunction(number) {  return function() {    alert("This is button number " + number);  }}function addButton(data) {  var newbutton = "<button>Click me</button>" //creates string from data  var element = document.getElementById("mydiv");  element.insertAdjacentHTML('afterbegin', newbutton);  var children = element.children;  children[0].onclick = createOnclickFunction(count)  count++;}addButton();addButton();addButton();
<div id="mydiv"></div>

Why can event listeners stop working after using element.innerHTML?

Most probably, it refers to the technique some people use to insert HTML at the end:

element.innerHTML += "inserted HTML";

This will get the current HTML, concatenate it with the inserted one, and parse it all.

As a side effect, all the internal state of the existing elements (like event listeners, checkedness, ...) will be lost.

var btn = document.querySelector("button");btn.addEventListener("click", function() {  btn.textContent = "I won't work anymore";  document.body.innerHTML += "<p>Inserted text</p>";});
<button>Click me to insert HTML</button>

Is it possible to append to innerHTML without destroying descendants' event listeners?

Unfortunately, assignment to innerHTML causes the destruction of all child elements, even if you're trying to append. If you want to preserve child nodes (and their event handlers), you'll need to use DOM functions:

function start() {
var myspan = document.getElementById("myspan");
myspan.onclick = function() { alert ("hi"); };

var mydiv = document.getElementById("mydiv");
mydiv.appendChild(document.createTextNode("bar"));
}

Edit: Bob's solution, from the comments. Post your answer, Bob! Get credit for it. :-)

function start() {
var myspan = document.getElementById("myspan");
myspan.onclick = function() { alert ("hi"); };

var mydiv = document.getElementById("mydiv");
var newcontent = document.createElement('div');
newcontent.innerHTML = "bar";

while (newcontent.firstChild) {
mydiv.appendChild(newcontent.firstChild);
}
}

Remove child nodes (or elements) or set innerHTML=?

I made a new test that isn't broken.

http://jsperf.com/innerhtml-vs-removechild/67

It's not perfect either since part of the sample setup is part of the test so this might skew the results.

This gives that innerHTML is faster but I don't know by how much.

Remove all child elements of a DOM node in JavaScript

In 2022+, use the replaceChildren() API!

Replacing all children can now be done with the (cross-browser supported) replaceChildren API:

container.replaceChildren(...arrayOfNewChildren);

This will do both:

  • remove all existing children, and
  • append all of the given new children, in one operation.

You can also use this same API to just remove existing children, without replacing them:

container.replaceChildren();

This is fully supported in Chrome/Edge 86+, Firefox 78+, and Safari 14+. It is fully specified behavior. This is likely to be faster than any other proposed method here, since the removal of old children and addition of new children is done without requiring innerHTML, and in one step instead of multiple.

How to remove the child element of a div in react using useRef hook?

You should indicate the child element in the removeChild() method.

chart.current.removeChild(chart.current.children[0])

addEventListener to innerHTML

I agree with you that theoretically the object should have the event, but the behavior we experience is that whenever another write happens at the relevant section of the DOM, the event handler is lost, which is the reason the last element has the click event. So, let's write first into the DOM and only when we are done with that should we add the event listeners, like:

let SoundCloudAPI = {};
SoundCloudAPI.init = () => {
SC.initialize({ client_id: 'cd9be64eeb32d1741c17cb39e41d254d' });
};
SoundCloudAPI.init();

SoundCloudAPI.getTrack = (inputVlue) => {
SC.get('/tracks', {
q: inputVlue
}).then((tracks) => {
console.log(tracks);
SoundCloudAPI.renderTracks(tracks);
});
}
SoundCloudAPI.getTrack("alan walker");

SoundCloudAPI.renderTracks = (track) => {

track.forEach(element => {

//this the card that will add the button for
let card = `<div class="card">
<div class="image">
<img class="image_img" src="${element.artwork_url || 'http://lorempixel.com/100/100/abstract/'}">
</div >
<div class="content">
<div class="header">
<a href="${element.permalink_url}" target="_blank">${element.title}</a>
</div>
</div>
</div >`;

//here i add the card to DOM
let searchResults = document.querySelector('.js-search-results');
searchResults.innerHTML += card;

// store the content of the button
let inBtn = `<i class="add icon"></i>
<span>Add to playlist</span>`;

// created button container
let btn = document.createElement("div");
btn.classList.add("ui", "bottom", "attached", "button", "js-button", "fresh");

// added the content of the button
btn.innerHTML += inBtn;


//here i add the button to the last card have been created
searchResults.querySelector(".card:last-child").append(btn);
});
for (let btn of document.querySelectorAll('.ui.attached.button.js-button.fresh')) {
// here i add the the event Listener to the button
btn.addEventListener('click', () => {
console.log("click");
});
}
}

Fiddle: https://jsfiddle.net/r84um9pt/



Related Topics



Leave a reply



Submit