Thursday 12 June 2008

Javascript event handling - a quick primer for beginners

Ok It has been a while since I had a techie slant to my posts. But this week gave me an excuse to dig deeper into the whys and wherefores associated with the JS event model which to be honest can be somewhat difficult to get your head around.

So if you are just new to javascript or have been afraid to wander around in the world of synthesizing events this post may be for you. Heaven knows I am a simple man replete with a complete set of simple pleasures (some of which are only legal in Kentucky) sadly the event model of the major browsers had passed me by, basically because most of the events I needed were already there so I just used them. However there comes a time in every geeks life when you have to hold your nose, ensure the drawstring on your coding speedos are tied on tight and just jump right in. Which is what I did this week when it became apparent that the order JS fires the events in was causing us accessibility problems. This is what I have learned ... and if one of the luminaries that might come across this post notices a fubar please let me know and I will correct it.

OK Event order

lets say you have two elements on inside the other like this (i'm using [] instead of<>)

[div id='div1' onclick='dothis()']
[span id='span1' onclick='dothat()'] Captian Carrot is Very Tall [/span]
[/div]

Your user clicks on the SPAN tag contents .. which fires both the SPAN and DIV events

"Thats Fair enuff"i hear you say, but what order does it do it in? Would it surprise you to know that there are 3 different models, IE , Mozilla and in the middle sitting on the fence spitting on both sides is the W3C model. ~sigh~

Mozilla says that the DIV event fires first then the SPAN - This is called capturing

IE says that the SPAN event fires first then the DIV - This is called bubbling

W3C will capture DIV,go down to the SPAN then bubble back up to the DIV again

Fascinating init?

Now this is were you the web developer rip of your shirt, sling a bandelero of bullets over your shoulder and tie your "popular computing " bandana around your head and get all Rambo with your code.

The addEventListener([event to listen for],[code to run],[type flag]) method allows you to choose which model you want. The important bit being the [type flag] which is boolean and if you set it to true the event is set to capturing if false it is set to bubbling.

So lets look at

[div id='div1']
[span id='span1'] Captian Carrot is Very Tall [/span]
[/div]

Note I have taken out the event handles from the HTML, instead I add them into the JS on the page. Like this

document.getElementById('div1').addEventListener('click',dothis,true)
document.getElementById('span1').addEventListener('click',dothat,false)

If the user clicks on the SPAN the following happens:

  1. The CLICK event starts in the capturing phase of DIV1 so

  2. The CLICK event on DIV1 fires namely dothis

  3. The event then shimmys down to the SPAN cos CAPTURE goes DOWNWARD
    and no more event handlers for the capturing phase are found.
    So the event then moves to its bubbling phase and there is a CLICK event so dothat() is executed.

  4. The event travels upwards again and checks if any element of the target has an event handler for the bubbling phase. This is not the case, so the event dies a natural death.
Now you could do this arse about face like this

document.getElementById('div1').addEventListener('click',dothis,false)
document.getElementById('span1').addEventListener('click',dothat,false)

Now if the user clicks on SPAN the following happens:

  1. Events start in the bubbling phase on SPAN1

  2. SPAN1's event is triggered and dothat() runs.

  3. Because Bubbling events go UP travel upwards -DIV1 is checked for
    for BUBBLING CLICK events.

  4. DIV1 does so dothis() is executed.
5. There are no more CLICK events registered on elements upwards in the doc so the event dies a natural death.

Now this is important .... bubbling or capturing will ALWAYS happen, that is unless you stop it.
If you wanted to stop the dothat from being processed after dothis you would do something like this to ensure that both major browser types stop were you want then to stop.
function dothis(e)
{
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
... rest of your code goes here ;
}

OK? Does that make sense?
I will expound more on events and the fun things you can do to mess with
your user's head in a future post.

Disqus for Domi-No-Yes-Maybe