user313724
user313724

Reputation: 3495

Event delegate with JavaScript

I have a list of divs, that I want to add "onmouseover" events to. I try to iterate over the list of elements, and redefine the "onmouseover" function like this:

for (var i=0; i<3; i++) {
   elements[i].onmouseover = function() { alert('FOO') }; 
}

Unfortunately, after the page finishes loading, it looks like this only gets applied to the very last element. I'm sure this is a real newbie question, but I still haven't figured it out...

Here's a better example exhibiting my problem: http://jsfiddle.net/qajPM/

Upvotes: 1

Views: 496

Answers (2)

nnnnnn
nnnnnn

Reputation: 150030

The problem is that you are creating all of your div elements like this:

parent.innerHTML += "<div> " + i + "</div>"

As I'm sure you know that is equivalent to parent.innerHTML = parent.innerHTML + ..., but the .innerHTML property returns the html as a string (without any already associated event handlers) so each time you do that it is overwriting the entire innerHTML of the parent div with a new string, which means you are effectively adding to the text contents but clobbering the mouseover handlers you've already setup.

Try instead something like this:

var el = document.createElement("div");
el.innerHTML = i;
parent.appendChild(el);

Which appends a new element without affecting the ones already there.

Updated demo: http://jsfiddle.net/qajPM/1/

Upvotes: 1

T. Stone
T. Stone

Reputation: 19485

One thing you can do is instead of assigning an event handler to every div, you could assign one handler to the parent, then simply fetch which div was moused over based on the event target.

HTML:

<div id="parent">
    <div>1</div>
    <div>2</div>
    <div>3</div>
</div>

Javascript:

document.getElementById('parent').onmouseover = function(e) {
    var target = e.target || e.currentTarget;
    alert('Target ' + target.innerHTML + ' was moused over');
};

Fiddle: http://jsfiddle.net/ZhpLA/

As others have pointed out jQuery also makes this have slightly less code (though if this is all you need it for it would be pointless):

$('#parent').on('mouseover', 'div', function(e) {
    alert('Target ' + e.currentTarget.innerHTML + ' was moused over');
});

The advantage to the above jQuery code is that it will apply both to current and future child divs of #parent. If you were to programatically add more the mouseover event would continue to work for them as well.

Upvotes: 2

Related Questions