Home Java Events bubbling and events capturing

Events bubbling and events capturing

by admin

Events bubbling and events capturing
Imagine there are two blocks onthe page, and one is nested within the other, as shown in the figure.In the page layout, it looks like this :

<div id="block_outer"><div id="block_inner"> </div></div>

Now imagine that the #block_outer block has the onClickOuter event attached to it, and the #block_inner block has the onClickInner event attached to it.And answer the question, how can I make it so that when I clickon the #block_inner block, the onClickOuter event is not called? And will it be called at all? And if so, in what order will the events be called? And do you know how jQuery.liveor similar methods work in other libraries (events delegation in ExtJS, for example)?

A bit of history

At the dawn of civilization, when dinosaurs walked over the planet and ancient IT people used stone-carved smartphones, the browser war was in full swing, MS and Netscape had a controversial opinion about the behaviorof events in web pages (luckily, I was not confronted with it at that distant time due to my age).If the elements on the page are nested (like in the above example), MS suggested the events bubbling model, which means that the order of events should bubble up in the DOM structure. Netscape proposed the opposite model, called event capturing, where event handling should bubbling down the elements ("capturing" them) in the DOM tree.
Events bubbling and events capturing
W3C tried to combine the two options – standard standard allows the programmer to set the behavior of events on the page by himself, using the third parameter of the method

addEventListener(type, listener, useCapture)

So when you click, the "down" phase will happen first and the events that are bound with the useCapture = true flag will be called, then the "up" phase will start and the other events will be called in the order they climb the DOM-tree. By default, events are always subscribed to the bubbling phase, that is, with this method of subscribing to the useCapture = false event:

elementNode.onclick = someMethod;

Events bubbling and events capturing

How do browsers handle this today?

The addEventListener method does not exist in IE below version 9. It uses attachEvent, which has no third argument, meaning events will always "gurgle" in IE, and much of what is described below makes no sense for that browser. All other browsers implement addEventListener according to the 2000 specification without derogation.
To summarize the above, let’s write a little test to show how you can control the priority of running events :

  • HTML structure:
    <div id="level1"><div id="level2"><div id="level3"></div></div></div>
  • Source :
    // using jQuery;jQuery.fn.addEvent= function(type, listener, useCapture) {var self = this.get(0);if (self.addEventListener) {self.addEventListener(type, listener, useCapture);}else if (self.attachEvent) {self.attachEvent('on' + type, listener);}}

    var EventsFactory = function(logBox){this.createEvent = function(text){return function(e){logBox.append(text + ' ');}}}var factory = new EventsFactory( $('#test') );$('#level1').addEvent('click', factory.createEvent(1), true);$('#level1').addEvent('click', factory.createEvent(1), false);$('#level2').addEvent('click', factory.createEvent(2), true);$('#level3').addEvent('click', factory.createEvent(3), false);
  • Demo

If you click on the #level3 block, the numbers will be displayed in the following order :

 1 2 3 1 

That is, blocks #level1 and #level2 are signed for the capturing phase, while #level3 and #level1 (signed again) are signed for the bubbling phase. The first to call the capturing phase is the one going down the tree, #level1 comes first, then #level2, the #level3 element itself comes next and then, going up the DOM, the #level1 element comes up again. Internet Explorer will show us :

 3 2 1 1 

How do I stop the next event from running?

Any of the bound events can stop the following elements from bypassing :

function someMethod(e) {if (!e) {window.event.cancelBubble = true;} else if (e.stopPropagation) {e.stopPropagation();}}

The W3C model describes the stopPropagation method of the event object, but Microsoft has distinguished itself here too, so for IE you need to refer to the event.cancelBubble field.

Event target

As you know, it is possible to identify the page element that initiated the event. The event object has a target field that refers to the triggering element. It’s easy to show this on the example of :

  • HTML structure:
    <div id="level1"><div id="level2"><div id="level3"></div></div></div>
  • Source :
    $('#level1').addEvent('click', function(e) {// MSIE "features"var target = e.target ? e.target : e.srcElement;if ( $(target).is('#level3') ) {$('#test').append('#level3 clicked');}}, false);
  • Demo

Let me explain what happens here – at any click inside #level1 we check event target and if the initiator is internal block #level3 we execute some code. Does this implementation remind you of anything? This is roughly how it works jQuery.live : if an element doesn’t exist on the page, but it will in the future, you can still bindan event to it. In the bubbling phase, any event reaches the document level, which is the common parent for all elements on the page, and this is where we can bind events that may or may not trigger certain functions, depending on event.target.
And here a question arises : if jQuery.live binds events to bubbling phase at document level, then it means previous events can stop the call chain and break the call of the last event? Yes it does, if one of the events running before it calls event.stopPropagation(), then the call chain is broken. Here is an example :

  • HTML structure:
    <div id="level1"><div id="level2"><div id="level3"></div></div></div>
  • Source :
    $('#level1').live('click', function(e){$('#test').append('#level1 live triggered');});$('#level2').bind('click', function(e){$('#test').append('this will break live event');if (e.stopPropagation) {e.stopPropagation();}});
  • Demo

Clicking on the #level3 area will display "this will break live event", that is, the live event will not be executed. Please note that such a hack is possible, it can be a nice implementation of something, and sometimes it can be a hard (hellishly hard) to catch bug.
It’s also important to note that in the example above, the "e" variable is an instance of jQuery.Event. The event has no stopPropagation method for IE, and you must set event.cancelBubble = true to stop bubbling in IE. But jQueryelegantly solves this problem by substituting its own method.

How do the different JS libraries handle events?

At this point I’ll point out that there are a lot of libraries that can handle events, but we will consider only jQuery, MooTools, Dojoand ExtJS, because this article and the author’s knowledge, unfortunately, are not enough. So those who like to discuss languages and frameworks please pass by.

  • jQuery
    knows how to handle events through bind which always binds events to the bubbling phase, but has a third parameter "preventBubble" which stops the event chain for that handler. There are also wrappers for it like click , change etc., and ways to delegateevents : delegate , live
  • MooTools
    knows how to handle events through addEvent which can handle custom events AddEvent also does not allow you to specify a processing phase. You can work with delegating events with pseude :relay
  • Dojo
    uses to bind events connect (which can also stop the event chain if "dontFix" is given) or behavior You can use the method delegate
  • ExtJS
    provides, in my opinion, the simplest interface for handling events. For the method on it is possible to pass parameters like delay, stopPropagation, delegate or custom arguments.

As we can see, all of these libraries compromise with cross-browser and use events bubbling everywhere, while providing similar functionality for event handling. However, understanding how it works from the inside out never hurts 🙂

Materials

You may also like