Javascript addEventListener inside loop

I am trying to add an event listener to some of the elements that I am generating in a loop. I have to use div.lastChild

- although in this example it's pretty silly. But this is just a demo:

<div id="someArea">
</div>
<script type="text/javascript">
    var func = function() {
        alert('Callback works');
    }

    var func1 = function() {
        alert('Test');
    }

    var func2 = function() {
        alert('Test2');
    }

    var div = document.getElementById("someArea");
    var callbacks = [func, func1, func2];
    for(var i = 0; i <= 2; i++) {
        div.innerHTML += '<input type="button" value="' + i + '" />';
        (function(i) {
            console.log(div.lastChild);
            div.lastChild.addEventListener('click', callbacks[i], false);
        }(i));

    }
</script>

      

The event only works for the last button. What am I missing here?

+3


source to share


1 answer


Why doesn't it work.

When you do ...

div.innerHTML += '<input type="button" value="' + i + '" />';

      

... on each iteration of the loop, you destroy the old DOM nodes inside div

(and therefore their handlers) and recreate the new nodes (but not the handlers). Destruction includes items input

that were added in previous iterations.

This is why only the last one works, since after that you assigned the handler to the last element and the others are completely new and untouched.


Decision.

Instead of treating the DOM as if it were a string of HTML markup, consider using DOM methods to create the element ...

for(var i = 0; i <= 2; i++) {
    var input = document.createElement('input');
    input.type = 'button';
    input.value = i;
    input.addEventListener('click', callbacks[i], false);
    div.appendChild(input);
}

      

Note that I removed the immediately callable function. This was not necessary for your code as it i

is evaluated in a loop, not later in the handler.




The DOM is not HTML, but it .innerHTML

makes you think it is.

It's important to understand innerHTML

. There is no HTML markup when working with the DOM. So when you get it .innerHTML

, the DOM is parsed and a new line of HTML is created.

When you assign .innerHTML

, you destroy all current content and replace it with new nodes created from the HTML string.

So when you ...

div.innerHTML += '<input...>'

      

... you first create a new HTML line from the current content, then concatenate the new HTML content into a string, then destroy the old nodes and create new ones from the new line.

This is terribly inefficient, and as you've seen, it destroys any data associated with the original elements, including handlers.


+3


source







All Articles