I hope someone can help me understand why the scenario below fails. I have a parent ul tag with an event handler that conditions for a given descendent li element in another ul tag nested within it. The markup is:
<ul id="outerUL">
<li>LIST ITEM 1</li>
<li>LIST ITEM 2</li>
<li>
<ul id="innerUL">
<li>LIST ITEM 3</li>
<li>LIST ITEM 4</li>
<li>
<ul id="inMostUL">
<li>LIST ITEM 5</li>
<li>LIST ITEM 6</li><!-- we condition for this element -->
<li>LIST ITEM 7</li>
</ul>
</li>
</ul>
</li>
</ul>
The javascript is: (it seems a conditional .stopPropagation() in an ancestor call fails...)
var outerMostUL = document.getElementById("outerUL");
outerMostUL.addEventListener('click',
function(e){
if(e.target.innerHTML === "LIST ITEM 6"){
e.stopPropagation();
alert("you clicked LIST ITEM 6. Event travel stops.");
// return; // a return WILL work
}
// below runs if propagation continues...
alert("outerMostUL event handler fired!");
},
false);
Now if i decide to put in a discreet .addEventListener() call on that li tag, .stopPropagation() works as expected, eg:
// A discreet event handler does work
var inMostUL = document.getElementById("inMostUL");
inMostUL.children[1].addEventListener('click', function(e){
e.stopPropagation();
alert("The descendent event fires, but stops now.");
});
So my question is: SHOULD you be able to use a condition in an ancestor's handler for a given e.target and stop propagation of its event, if bubbling is enabled? It seems that an element must have its own handler bound to originate an event, but perhaps I confuse a propagating event traveling the ancestor chain with actually adding an event listener via that method. Any light shedding will be greatly appreciated. I'm am just trying to conceptualize js event handling through simple examples. Thanks for any consideration of this.
The event bubbling propagation can be stopped with e.stopPropagation()
at any point along the ancestor chain and that will stop the event from propagating any further up to other ancestors.
And, there's no issue with stopping propagation conditionally only under certain circumstances.
I think some of your confusion just has to do with your javascript function, not with propagation. In this code:
var outerMostUL = document.getElementById("outerUL");
outerMostUL.addEventListener('click', function(e){
if(e.target.innerHTML === "LIST ITEM 6"){
e.stopPropagation();
alert("you clicked LIST ITEM 6. Event travel stops.");
}
// below runs ALWAYS, regardless of the result of the previous "if" statement
alert("outerMostUL event handler fired!");
}, false);
The second alert happens without the return
statement NOT because of propagation, but just because your javascript function continues to execute after the conditional if
block. This has nothing to do with propagation, but just with javascript program flow. If you add the return
statement, you are ending your event handler callback early so the rest of it is not executed. Without the return
statement, execution in that function continues after the if
block whether the if
statement is satisfied or not.
In conceptually understanding event propagation, just think of a piece of code in the browser that initiates an event that bubbles. That event is first sent to the event handler of the target object and if propagation isn't canceled there, it is then sent to the next ancestor and if propagation isn't canceled there, it is then sent on up the ancestor chain until it gets to the document
object or until propagation is canceled.
Also, keep in mind that if you aren't using a cross-platform library like jQuery and you want to support older versions of IE that the stopping of propagation works differently in those older versions of IE.