Search code examples
javascriptdom-eventsevent-bubbling

What is the default event order in JavaScript? Top-down or Bottom-up?


Possible Duplicate:
What is event bubbling and capturing

I just learnt that in JS we have two event types: Capture and Bubble. Bubble can be used for avoiding the need of attaching the eventListener to all children; instead attach listener only to the parent and have it check the target. It sounds cool. And I tried out this example:

<div id="parent-list">
    <span>span1</span>
    <span class='target'>span2</span>
    <span>span3</span>
    <span>span4</span>
</div>

<script type="text/javascript">
document.getElementById('parent-list').addEventListener('click',function(e){
    if( e.target && e.target.nodeName=='SPAN' ){
        var classes = e.target.className.split(' ');
        for(var i=0; i<classes.length; ++i){
            if( classes[i]=='target' ){
                alert('Bingo! you hit the target.');
            }
        }
    }
});
</script>

But I haven't attached any listeners to the child spans. Yet the events on them are bubbling! So is bubbling the default event order in JS? Then in which scenario would the capture (top-down) be used?


Solution

  • Imagine you have html that looks like this:

    <div id="grandparent">
        <div id="parent">
            <button id="target"></button>
        </div>
    </div>
    

    And JS which looks like this:

    function sayGrandpa (evt) { console.log("Grandpa"); }
    function sayClicked (evt) { console.log("Clicked"); }
    
    var grandparent = document.getElementById("grandparent"),
        target = document.getElementById("target");
    
    grandparent.addEventListener("click", sayGrandpa, false);
    target.addEventListener("click", sayClicked, false);
    

    Bubbling vs Capture doesn't really have anything to do with what you're supposing, in that in both cases (on W3C-compliant browsers), you can use event listeners to attach to a parent, to listen to events which are triggered on a child.

    The difference is that bubbling assumes that the chain of events starts at the target, and works its way back up through the chain of parents, like a bomb detonating at ground-zero, and sending a shockwave rippling outward.

    Capturing starts at window (or at <html>), and goes down to the target element.

    So when you use bubbling (more like rippling), any functions which are set directly on the element happen first, and any delegated functions, attached to ancestors, happen as the ripples go back up the chain.

    When you use capturing, any delegated functions, attached to ancestors, happen BEFORE the event happens on the element.
    So the grandparent element knows about a click, before target does.

    So when you ask what order things happen in, things are pretty obvious:

    When you set an event on grandparent which is captured and set a second event on grandparent which is bubbled, and set an event on target which is either, the order will be:

    captured grandparent target bubbled grandparent

    So when is it beneficial to have ancestors know about a click happening before the button that's actually being clicked?
    Great question!

    I'm sure somebody can think of something that isn't just a really-douchey way of making people miserable by hiding the thing they were supposed to be clicking on.

    But the moral is that you expressly have to ask for it (setting the third parameter of .addEventListener to true).
    Also, oldIE and others don't support capturing at all.

    It's not really something which should be used in general.