By mike


2009-02-27 17:43:14 8 Comments

In the following example code, I attach an onclick event handler to the span containing the text "foo". The handler is an anonymous function that pops up an alert().

However, if I assign to the parent node's innerHTML, this onclick event handler gets destroyed - clicking "foo" fails to pop up the alert box.

Is this fixable?

<html>
 <head>
 <script type="text/javascript">

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

    mydiv = document.getElementById("mydiv");
    mydiv.innerHTML += "bar";
  }

 </script>
 </head>

 <body onload="start()">
   <div id="mydiv" style="border: solid red 2px">
     <span id="myspan">foo</span>
   </div>
 </body>

</html>

13 comments

@AKS 2019-07-21 09:08:08

For any object array with header and data.jsfiddle

https://jsfiddle.net/AmrendraKumar/9ac75Lg0/2/

<table id="myTable" border='1|1'></table>

<script>
  const userObjectArray = [{
    name: "Ajay",
    age: 27,
    height: 5.10,
    address: "Bangalore"
  }, {
    name: "Vijay",
    age: 24,
    height: 5.10,
    address: "Bangalore"
  }, {
    name: "Dinesh",
    age: 27,
    height: 5.10,
    address: "Bangalore"
  }];
  const headers = Object.keys(userObjectArray[0]);
  var tr1 = document.createElement('tr');
  var htmlHeaderStr = '';
  for (let i = 0; i < headers.length; i++) {
    htmlHeaderStr += "<th>" + headers[i] + "</th>"
  }
  tr1.innerHTML = htmlHeaderStr;
  document.getElementById('myTable').appendChild(tr1);

  for (var j = 0; j < userObjectArray.length; j++) {
    var tr = document.createElement('tr');
    var htmlDataString = '';
    for (var k = 0; k < headers.length; k++) {
      htmlDataString += "<td>" + userObjectArray[j][headers[k]] + "</td>"
    }
    tr.innerHTML = htmlDataString;
    document.getElementById('myTable').appendChild(tr);
  }

</script>

@Kamil Kiełczewski 2019-05-02 20:41:13

Yes it is possible if you bind events using argument onclick="sayHi()" directly in template similar like your <body onload="start()"> - this approach similar to frameworks angular/vue/react/etc. You can also use <template> to operate on 'dynamic' html like here. It is not strict unobtrusive js however it is acceptable for small projects

function start() {
  mydiv.innerHTML += "bar";
}

function sayHi() {
  alert("hi");
}
<body onload="start()">
  <div id="mydiv" style="border: solid red 2px">
    <span id="myspan" onclick="sayHi()">foo</span>
  </div>
</body>

@Anoop Anson 2018-10-24 08:07:30

The easiest way is to use an array and push elements into it and then insert the array subsequent values into the array dynamically. Here is my code:

var namesArray = [];

function myclick(){
    var readhere = prompt ("Insert value");
    namesArray.push(readhere);
    document.getElementById('demo').innerHTML= namesArray;
}

@KawaiKx 2018-07-12 18:45:54

something.innerHTML += 'add whatever you want';

it worked for me. I added a button to an input text using this solution

@demo7up 2019-09-19 13:38:01

This was the most simplest method ive come across thank you!

@Tural Asgar 2019-11-06 20:30:26

It destroys all events.

@Danish 2019-11-20 12:30:23

how is it really a solution? it destroys all the events!!

@Frank Conijn 2018-06-27 03:48:35

There is another alternative: using setAttribute rather than adding an event listener. Like this:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Demo innerHTML and event listeners</title>
<style>
    div {
        border: 1px solid black;
        padding: 10px;
    }
</style>
</head>
<body>
    <div>
        <span>Click here.</span>
    </div>
    <script>
        document.querySelector('span').setAttribute("onclick","alert('Hi.')");
        document.querySelector('div').innerHTML += ' Added text.';
    </script>
</body>
</html>

@Josh de Leeuw 2016-12-07 16:35:10

Using .insertAdjacentHTML() preserves event listeners, and is supported by all major browsers. It's a simple one-line replacement for .innerHTML.

var html_to_insert = "<p>New paragraph</p>";

// with .innerHTML, destroys event listeners
document.getElementById('mydiv').innerHTML += html_to_insert;

// with .insertAdjacentHTML, preserves event listeners
document.getElementById('mydiv').insertAdjacentHTML('beforeend', html_to_insert);

The 'beforeend' argument specifies where in the element to insert the HTML content. Options are 'beforebegin', 'afterbegin', 'beforeend', and 'afterend'. Their corresponding locations are:

<!-- beforebegin -->
<div id="mydiv">
  <!-- afterbegin -->
  <p>Existing content in #mydiv</p>
  <!-- beforeend -->
</div>
<!-- afterend -->

@Tural Asgar 2019-11-06 20:31:49

You saved my day!

@Dawoodjee 2019-11-24 13:47:47

Best solution. Thank you!

@Rishabh gupta 2014-03-27 19:14:25

You could do it like this:

var anchors = document.getElementsByTagName('a'); 
var index_a = 0;
var uls = document.getElementsByTagName('UL'); 
window.onload=function()          {alert(anchors.length);};
for(var i=0 ; i<uls.length;  i++)
{
    lis = uls[i].getElementsByTagName('LI');
    for(var j=0 ;j<lis.length;j++)
    {
        var first = lis[j].innerHTML; 
        string = "<img src=\"http://g.etfv.co/" +  anchors[index_a++] + 
            "\"  width=\"32\" 
        height=\"32\" />   " + first;
        lis[j].innerHTML = string;
    }
}

@Eneroth3 2012-07-04 08:08:16

I created my markup to insert as a string since it's less code and easier to read than working with the fancy dom stuff.

Then I made it innerHTML of a temporary element just so I could take the one and only child of that element and attach to the body.

var html = '<div>';
html += 'Hello div!';
html += '</div>';

var tempElement = document.createElement('div');
tempElement.innerHTML = html;
document.getElementsByTagName('body')[0].appendChild(tempElement.firstChild);

@rocketsarefast 2012-01-20 18:06:15

Now, it is 2012, and jQuery has append and prepend functions that do exactly this, add content without effecting current content. Very useful.

@Esailija 2012-07-23 13:47:30

.insertAdjacentHTML has been around since IE4

@Jordon Bedwell 2016-11-25 14:37:51

@Tynach yes it does, it's their JavaScript site that documents it the best: developer.mozilla.org/en-US/docs/Web/API/Element/…

@Tynach 2017-09-09 03:15:26

@JordonBedwell, I honestly have no idea why I said what I did before. You're 100% right. I feel like at the time I briefly looked into it and couldn't find it, but... Honestly I have no excuse. Esailija even links to that page.

@André Marcondes Teixeira 2019-10-15 19:52:53

OP is not talking about jQuery

@lucious 2010-07-09 14:46:13

I'm a lazy programmer. I don't use DOM because it seems like extra typing. To me, the less code the better. Here's how I would add "bar" without replacing "foo":

function start(){
var innermyspan = document.getElementById("myspan").innerHTML;
document.getElementById("myspan").innerHTML=innermyspan+"bar";
}

@wlf 2012-11-23 10:45:15

This question is asking how to do this without losing event handlers, so your answer is not relevant, and btw this is what += does, which is way shorter

@JLRishe 2017-10-20 19:17:04

It's hilarious that in this completely wrong answer that cites avoiding extra typing as a justification, about half the code is redundant.

@Cargowire 2009-02-28 13:05:32

As a slight (but related) asside, if you use a javascript library such as jquery (v1.3) to do your dom manipulation you can make use of live events whereby you set up a handler like:

 $("#myspan").live("click", function(){
  alert('hi');
});

and it will be applied to that selector at all times during any kind of jquery manipulation. For live events see: docs.jquery.com/events/live for jquery manipulation see: docs.jquery.com/manipulation

@André Marcondes Teixeira 2019-10-15 19:53:06

OP is not talking about jQuery

@Ben Blank 2009-02-27 17:47:07

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);
    }
}

@mike 2009-02-27 17:55:38

Is there a substitute that can append an arbitrary blob of HTML?

@bobince 2009-02-27 18:13:10

newcontent= document.createElement('div'); newcontent.innerHTML= arbitrary_blob; while (newcontent.firstChild) mydiv.appendChild(newcontent.firstChild);

@mike 2009-02-27 18:17:11

Nice, Bob! If you post that as a well-formatted answer, I'll select it.

@Ben Blank 2009-02-27 20:25:30

@bobince — I've updated my answer with your technique, since you haven't posted it yet yourself. If you create your own answer, go ahead and roll mine back. :-)

@Crescent Fresh 2009-02-27 20:33:07

@Ben: you don't need the call to newcontent.removeChild(). Bob's original comment was correct.

@Ben Blank 2009-02-27 21:01:56

@crescentfresh — If you don't remove the child node from newcontent, while (newcontent.firstChild) loops forever. Try it.

@Ben Blank 2009-02-27 21:09:45

Hmm… I take that back. It shouldn't loop — I have no idea what was going wrong the first time I tested it. :-/

@bobince 2009-02-27 21:24:26

Oh, one last thing, you'll want “var myspan”, “var newcontent” etc. to avoid accidentally spilling globals.

@Ben Blank 2009-02-27 21:58:25

Heh. It's becoming apparent that my tendency to bash out quick & dirty example/prototype code doesn't serve me well on SO. :-)

@Yes - that Jake. 2009-02-27 17:48:44

Losing event handlers is, IMO, a bug in the way Javascript handles the DOM. To avoid this behavior, you can add the following:

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

  mydiv = document.getElementById("mydiv");
  clickHandler = mydiv.onclick;  // add
  mydiv.innerHTML += "bar";
  mydiv.onclick = clickHandler;  // add
}

@Diodeus - James MacFarlane 2009-02-27 17:51:02

I don't consider this a bug. Replacing an element means you completely replace it. It should not inherit what was there before.

@mike 2009-02-27 17:53:58

But I don't want to replace an element; I just want to append new ones to the parent.

@Yes - that Jake. 2009-02-27 17:57:40

If you were replacing the element, I would agree, @Diodeus. It's not the .innerHTML that has the event handler, but the .innerHtml's parent.

@bobince 2009-02-27 18:16:49

The innerHTML's owner does not lose handlers when its innerHTML is changed, only anything in its contents. And JavaScript doesn't know that you are only appending new children, since “x.innerHTML+= y” is only syntactical sugar for the string operation “x.innerHTML= x.innerHTML+y”.

@Crescent Fresh 2009-02-27 20:35:22

You don't need to re-attach mydiv.onclick. Only the inner span's onclick is overridden by innerHTML +=.

Related Questions

Sponsored Content

6 Answered Questions

[SOLVED] Javascript - Append HTML to container element without innerHTML

15 Answered Questions

[SOLVED] What's the effect of adding 'return false' to a click event listener?

  • 2008-09-24 18:28:54
  • Leonel
  • 420191 View
  • 350 Score
  • 15 Answer
  • Tags:   javascript html

21 Answered Questions

[SOLVED] Is it possible to simulate key press events programmatically?

18 Answered Questions

3 Answered Questions

[SOLVED] Cannot display HTML string

10 Answered Questions

[SOLVED] Is it possible to listen to a "style change" event?

  • 2010-01-28 21:09:10
  • David Hellsing
  • 142688 View
  • 190 Score
  • 10 Answer
  • Tags:   javascript jquery

3 Answered Questions

4 Answered Questions

[SOLVED] Adding multiple onload handlers

1 Answered Questions

[SOLVED] Jquery problem with IE

  • 2011-02-11 08:03:26
  • user612703
  • 508 View
  • 0 Score
  • 1 Answer
  • Tags:   jquery html ajax

2 Answered Questions

[SOLVED] Any idea why the X,Y position of this element is 0,0?

Sponsored Content