Filed under JS

Manipulating innerHTML removes events

Others have written about this before, but I thought I’d mention it again, just so you don’t miss it. Aleksandar Vacić found it while playing with tables and their cells. I found it when Robert and I played with nested lists. It works the same across browers. Let me show a quick example:

You have a paragraph tag that contains a span that you want to make clickable.

<p id="para">
   <span id="clickspan">This is clickable.</span>
   But this is not.
</p>

To make it clickable you don’t do any fancy stuff, you just add it with onclick:

var span = document.getElementsById("clickspan");
span.onclick = function() {
   alert("You clicked the span!");
}

All fine. You click the span and it just works. But then you remember something. You want to add some text to the end of the paragraph, and you decide to do this with javascript. You add the following line to the end of the script:

var p = document.getElementById("para");
p.innerHTML += " Some extra text";

You try clicking the span again, and it doesn work. You scratch your hair, you bite your nails, you scream of desperation and anger. It still doesn’t work. It seems manipulating an element by using innerHTML removes all events from that element, and all children. Here’s a live example. I thought you should know.

Feel free to leave a comment, or subscribe to my feed.

related

List some related articles:

You might want to browse all articles.

linkback

These people have linked to this article:

To get a link in this list: make sure your blogging software supports trackbacks or pingbacks and simply link to this article like this:

<a href="http://friendlybit.com/js/manipulating-innerhtml-removes-events/">Manipulating innerHTML removes events</a>

You can also trackback by copying this link, and pasting it into a trackback field in your blogging tool.

about

Author: Emil Stenström

Emil Stenström blogs about web development. Posts are bi-weekly.

To the about section

comments

What do you think about this article? I’d love to hear your view!

Scroll to comment box.

  1. Nate Klaiber 27 Sep

    01

    thats why you avoid using innerHTML :)

    Just kidding. Do you have the same results if you were to try appending via the DOM instead of innerHTML?

  2. Emil Stenström 27 Sep

    02

    @Nate: No, using DOM methods instead keeps the events as they should be. That’s one workaround. The other one is to attach events after using innerHTML.

  3. Freddy 27 Sep

    03

    I’ll have to call ‘duh’ on that one. Obviously, events on an element cannot be retained if the element is replaced by a completely different string using innerHTML. You basically throw away that part of the DOM and write it new. Don’t have to tell you that.

    The only thing slightly noteworthy is that this also applies when using the + unary operator (”+=”). And given that it is required to call GetValue() and return the sum, which is in turn written back as a whole, it is not very surprising.

  4. Emil Stenström 27 Sep

    04

    @Freddy: Good that you found it obvious, I just had to think for a while before it came to me. I thought I might save someone’s time by stating it, but deeming by your tone I might have been wrong about that.

    As you said, the confusing part here is that adding to and replacing innerHTML is the same.

    Thanks for commenting.

  5. Freddy 27 Sep

    05

    @Emil: I didn’t want to sound elitist, sorry if it came across as such. JFTR: In JavaScript, there is no “adding to” strings; Adding using the unary + (”+=”) is just a “shorthand” for reading, adding, and reassigning values (internally, they convert number/string types, but that’s not relevant in this context).

  6. Emil Stenström 27 Sep

    06

    @Freddy: Ah, thanks. It makes even more sense then.

  7. Johan Lind 27 Sep

    07

    Hmm, nothing happens when I click on any of those elements in Safari and Camino.
    Is this an IE only thing?

  8. Kalle Persson 27 Sep

    08

    Nice, I did not know this.

    Johan Lind:
    Look at the source of the example page, the JavaScript isn’t supposed to do anything when you click the span, because of the innerHTML change.

  9. Jose Carrero 27 Sep

    09

    Maybe i’m missing something but why add the onClick event using span.onclick=function()?, if you put the “onClick” inside the HTML tag it works fine even after the innerHTML change

  10. Ara Pehlivanian 28 Sep

    10

    Yeah, I came across this problem when writing an Ajax driven playlist for a project here at work. I was adding the new contents to the DOM with innerHTML and had to rebind all of the events for the entire list every time. Using DOM methods though will avoid this problem.

  11. Robert Nyman 28 Sep

    11

    Freddy,

    Thanks for explaining that! It threw us off for a while, so we just needed to think in alternate terms. In this case it was an AJAX call that could return any kind of HTML code, so using proper DOM methods wasn’t a viable option.

  12. Emil Stenström 28 Sep

    12

    @Jose Carrero: Many believe (including me) that adding things inline in the code like that is littering. You attach behaviour into the structure of the document. JS files should add their events from an external file, with onclick or something fancier.

  13. Anders Ringqvist 3 Oct

    13

    A viable soultion could be to use event delegation instead of ”classic” event handling.

    I let Christian Heilmann speak:

    http://icant.co.uk/sandbox/eventdelegation/

  14. Emil Stenström 4 Oct

    14

    @Anders Ringqvist: Very interesting technique, thanks for linking! If I understand it correctly it’s simply setting a listener on the outermost element, and waiting for the event to bubble there. Good way to avoid this problem.

  15. zcorpan 2 Jan

    15

    Another way around this problem is to create your own appendHTML() method like so:

    HTMLElement.prototype.appendHTML = function(s) {
    var div = document.createElement(’div’);
    div.innerHTML = s;
    while (div.firstChild)
    this.appendChild(div.firstChild);
    }

    This does what you thought “innerHTML +=” did (except that script blocks inserted this way will be executed).

If you want to you can follow the disussion through a comment feed.

add comment

This is the place where you get to say your opinion about this article, use it well. Formating with HTML is allowed. A red asterisk means that the following field is required.

Comment Form




Comment Form