views:

44

answers:

3

This html:

<span id="mySpan"><img src="images/picture.png" alt="Some nice alt text" />
 Link text</span>

This javascript takes the span containing the image and text, then makes it clickable:

spanVar = document.getElementById("mySpan");
spanVar.addEventListener("click", myEvent, false);

function myEvent(e){
 var obj = e.target;
}

If I click on the "Link text," then the obj in myEvent() is the span. If I click on the image, then the obj is the image element! The image itself has no event. So why isn't it always the span that gets passed to the event handler?

This is trimmed down so that it only works in Firefox for the sake of simplicity, by the way.

Also, please feel free to edit my question title if you can formualate it more coherently.

+2  A: 

You need to read up on event bubbling.

mikerobi
WHAT THE ...? How is this possible?! Take a look at my answer, 59 seconds later...
Harmen
Ah, a nice keyword to look up. These kind of answers are so vague and yet so helpful. Thanks. :-)
randomable
@Harmen: Great minds think alike :P
BoltClock
ahah I google 'javascript events bubbling' to also add a link to an article that explains the basic of bubbling and that's the first one that shows up so...
SBUJOLD
@Harmen, I must have submitted my answer after you opened the question, but before you clicked submit.
mikerobi
Poor Harmen. Now whose answer am I supposed to choose?
randomable
@randomable, Personally, when I post a duplicate answer moments after someone else, I remove it. I would say the only fair way would be to always pick the first.
mikerobi
@mikerobi, I agree, but I still feel bad for Harmen. :-P
randomable
The problem really isn't event bubbling. It's that all child elements of a parent element effectively receive the event handlers of their parent element. Event bubbling would come into play if the child and parent had different handlers attached, but you only wanted to fire the handler of the child.
Peter Ajtai
@Peter Ajtai, Actually, bubbling referees to the process of propagating events through the DOM hierarchy, regardless of what or where event handlers are attached.
mikerobi
@mikerobi - It's just confusing since event bubbling refers to event propagating up (to ancestors) through the DOM, and the OP seems to be asking about the attachment of event handlers down (to descendants) the DOM to the descendants of elements.
Peter Ajtai
+2  A: 

You should take a look at this article of Peter-Paul Koch on Quirksmode, it's exactly answering your question in detail

Harmen
Not sure if the article answers OP's question. The article is discussing the case where the child and parent have different handlers attached. The OP is trying to understand why events are inherited by child elements.
Peter Ajtai
+2  A: 

Events are effectively inherited.

When an event handler is added to an element, then all the children also are affected by that event handler, since they are inside the element. So you must deal with events carefully.

In your case, you just really want to check what is being clicked on inside myEvent:

spanVar = document.getElementById("mySpan");
spanVar.addEventListener("click", myEvent, false);

function myEvent(e){
    if (e.target === spanVar) // This will make the img non clickable
        var obj = e.target;
}

Try it out with this jsFiddle


If you want to retrieve the element that originally had the click handler attached to it, then simply use this

spanVar = document.getElementById("mySpan");
spanVar.addEventListener("click", myEvent, false);

function myEvent(e){
    var obj = this;  // This is the object that had the click handler attached
}

Try it out with this jsFiddle


The problem really isn't event bubbling. It's that all child elements of a parent element effectively receive the event handlers of their parent element. Event bubbling would come into play if the child and parent had different handlers attached, but you only wanted to fire the handler of the child.

Another solution is to change your HTML:

<div>
    <img src="images/picture.png" alt="Some nice alt text" />
    <span id="mySpan">Link text</span>
</div>
Peter Ajtai
Why you like your "Try it out" links so big?
Roatin Marth
@Roatin - Because the rest is just talk. I like to walk ;)
Peter Ajtai
So I had have to make a new version of myEvent() for every single element that ever triggers it? Is javascript really that badly made?
randomable
@randomable - What do you mean? No. You only have to make one event handler for the `<span>`. If you don't want the children to have the same handlers, then you can simply use `if(e.target === spanVar)`. Children are inside their parents, so you have to deal with that, just like you have to deal with it in CSS, etc. ----- Maybe if you described how you're trying to use this, that'd make things clearer.
Peter Ajtai
@Peter Ajtai, I just want to get the e.target of something that I set as clickable, not get a child element which I never set an event for. I'm starting to hate javascript. >_<
randomable
I'm starting to think the lesson here is to not make clickable spans or divs, but to iterate through each individual element in the span and make each one clickable instead.
randomable
@randomable - Oh. Just use `var obj = this`, since `this` is the element with the click handler. I didn't get that that's what you wanted to do.
Peter Ajtai
It's that simple? *facepalm* Thanks a lot.
randomable