JavaScript events are created in response to user actions such as clicks, mouse moves or key presses; not all events are triggered by user actions though, some are automatic such as the onPageLoad event. JavaScript’s event model allows developers to write event handlers which respond to these events and provide the interactivity we have come to love.
Most JavaScript code is written around events; when an event is fired, your handling code is triggered and a response is created for that action. For example, when a user clicks a send button, an AJAX call is initiated and the page is updated with new data. Or when you like this blog post, event handling is also involved. :)
Event models were created while the browser wars were raging – hence it’s not surprising both parties chose incompatible models; the W3C model came out even more recently. Due to these inconsistencies, it is quite difficult to get event handlers to work across all browsers however the good news is that a lot of libraries (e.g. the ubiquitous jQuery) handle the gory details for you.
Whose Event is it?
Suppose an element and one of its parents have event handlers for the same event (say a click or hover event), which one should fire first? The parent? The child?
As you’ll expect, the Microsoft and Netscape models differ: the Microsoft approach is called event bubbling i.e. events start from the child and propagate up to the parent (i.e. bubbling). The Netscape approach is called event capturing, the parent’s handler is triggered first and then the event is passed on to children.
Assuming a click event happens on the click area below:
<div> <span>Click area </span></div>
Capture mode: The div’s click handlers will be triggered first followed by the span’s handlers.
Bubble mode: The span’s click handlers will be triggered first and then the div’s handlers will fire.
The W3C specification supports both approaches: events are first ‘captured’ progressively until the target element is reached; next, the events bubble up from the target element. I wonder why this two-stage approach is preferred; sounds like more work to me.
Catch that event!
The addEventListener(type, listener, useCapture) method is the way to go about it, you specify the event type, handler function and whether to use the capture or bubble mode as the three parameters. Passing in false as the third argument creates the bubbling mode while passing in true initiates the capture model.
You can also stop events from bubbling or propagating beyond a certain element. Just call event.stopPropagation() (W3C browsers) or set event.cancelBubble = true (for IE < 9) in the event handler.
Whose event art thou?
To access the original source of the event, i.e. the element on which the event was triggered, you use the event.target (Netscape-y browsers) or event.srcElement (IE-y browsers). What if it’s being captured or bubbling? It doesn’t matter – this reference always points to the culprit.
However, say your event is bubbling up or capturing down ( I just invented that ), and you want to check the current element, you can use the event’s currentTarget property. This has a reference to the HTML element that the event is being handled by, for example a parent element. Unfortunately, this is not supported in the Microsoft event model.
To Capture or to Bubble?
Capturing has been shown to have a slight performance advantage over bubbling while bubbling can be used to cut the number of event handlers you need. For example, you can put a handler on a container that will capture all events on child elements when they bubble up. I like this approach because it saves you from having to add new listeners whenever a new child is added to the container.
You most probably won’t need to write your event handling code these days; but knowing how things work is always good, not so?
Do you like this post? Check out my other posts on JavaScript, its functional programming parts and a book review.
very clear and concise explanation. thank you!
LikeLike
Thank you! Am glad you liked it! :)
LikeLike