Intro to JavaScript Events
Background

The term event refers to something that happens to elements (by elements, we mean html elements such as <table>, <form>, <button>, or <div> ). For example, when clicking a <button>, there are several events taking place: mouse button being pushed, mouse button being released, and a html button being clicked.

Events are sent as notifications to JavaScript. When event occurs, they are being fired. JavaScript can intercept events by overridding the event handlers.

For example, to catch onclick events on this button:

<input type="button" value="Button"/>

Then one way to do it is like below (this particular example, when we intercept the event, we show an alert box saying "button clicked"):

<input onclick="javascript:alert('button clicked');return true;"
  type="button" value="Button"/>

Events can also be intercepted to trigger a function call. For example, below, the same onclick event triggers the handleOnClick function which we created somewhere else on the html page.

<script language="javascript">
  function handleOnClick()
  {
    alert(this);    
  }
</script>

[other html ....]

<input onclick="handleOnClick" type="button" value="Button"/>

The other two events can be intercepted, too. For example, the button below intercepts onmousedown, onmouseup, and onclick:

<input
  onclick="javascript:alert('button clicked');return true;"
  onmousedown="javascript:alert('button down');return true;"
  onmouseup="javascript:alert('button up');return true;"
  type="button" value="Button"/>

Notice that there are a sequence of order of the events: onmousedown, onmouseup, then onclick. The order could be important on some programming purposes.

Default Event Handler And Return Value

By assigning an event handler like above, our handler will be called before the default (built-in) event handler is called. Ont thing that often gets overlooked is the return value. This value is important in some sitations because that value determines whether the default event handler is called or not.

Returning false tells the default event handler to be skipped. Returning true tells the event-chain to continue (meaning the default event handler will be called). If no return value is specified, true is assumed.

To see the effect, see this example. The first text-field returns true and the second one returns false. Notice that by returning false, the default event handler is not called, and thus you cannot type onto the second text-field (this is useful for form validation, for example if user typed an alphabet into a phone number, you can reject it right away by returning false).

<input onkeydown="javascript:return true;" type="text" name="textfield" />
<input onkeydown="javascript:return false;" type="text" name="textfield" />


This return value may be useful (for example during in form validation, if the user's input is valid, we can just return true to let the default event handler take over).

Another frequent technique is to assign a script to a link without returning anything like the first example below. Click the two links below and see how they behave differently.

<a class="contentlink" href="#" 
onclick="javascript:alert('do something');"> <a class="contentlink" href="#"
onclick="javascript:alert('do something');return false;">

Click here to execute a JavaScript function and retuning nothing (true)

Click here to execute a JavaScript function and retuning false

On the first link, the default handler is called. Since nothing is returned. The default handler tries to jump to the anchor, which cause the anchor (#) to be appended in the browser bar (and possibly the html page to be scrolled to the top).

The second one does not do that because we return false to stop the default handler. In most cases, the later is what we really want so it is a good idea to pay attention to this return value.

Event Capturing And Bubbling

There are three phases that every event travels in the event chain: capturing phase, target phase and bubbling phase. Event capturing phase is when event is being sent from the container all the way down to the target element. Event bubbling refers to the way events are propagated upward to its ancestors after it reaches its target element.

Target phase is when the event actually is being sent to the target element that originated the event.

Consider the button below, contained within a <form> contained within <body>.

The capturing phase goes the root element, all the way to <button>.

When it reaches the button, that is the target phase. The bubbling phase goes in the opposite direction. After the event reaches the target (buttton), it goes back all the way to the top ancestor.

All the major current browsers supports the bubbling phase model, but some do not support the capturing phase. We will discuss event capturing more when discussing addEventListener() below.

to demonstrates event bubbling, we assign an onclick for every element in the following example. Click the button and you will see the event propagates up to its parents. Even though you only clicked the button, its ancestors also receive the event:

<body onclick="javascript:alert('body clicked');">
  <form onclick="javascript:alert('form clicked');">
<input onclick="javascript:alert('button clicked');" name="Button" type="button"> </form>
</body>

Open this page and click the button to try. You will see alert boxes in the order of the event received: the "button clicked" message, then "form clicked," then "body clicked."

This can be useful as we see in the example later, but it can also be undesirable to keep the bubbling on some situations. There's a way to break the bubbling-chain by setting the cancelBubble property of the event object to false.

event.cancelBubble=false;
Modifying our example and setting cancelBubble to false in the button:
<body onclick="javascript:alert('body clicked');">
  <form onclick="javascript:alert('form clicked');">
<input onclick="javascript:alert('button clicked');event.cancelBubble=false;"
name="Button" type="button"> </form>
</body>
Open this page and click the button to see how the event stops propagating and no longer triggers the parent event handlers.

For completeness, we're going back to capturing phase. The recommended method of event handling by DOM3 standard is to use addEventListener() method.

addEventListener(event string, 
listener (function or an Object implementing EventListener),
useCapture);

Where useCapture is a boolean value that indicates that the event of the specified type (example: "click" event) to be sent to the designated listener by the designated element during the capture phase (refer to the diagram above). Son that in this example below, the body will receive the notification before the event reaches the button:

document.body.addEventListener("click", function(){alert("body clicked");}, true);
document.getElementById("button").onclick=function(){alert("button2 clicked");

Try it here.

If the useCapture event above is set to false, then the event will be sent to the listener during the bubbling-phase, which means button will fire first before body.

The bad news is addEventListener() is currently not supported in Internet Explorer 7. In IE, you need to use this instead (which lacks the last parameter):

attachEvent(event string, 
listener (function));

I won't discuss this further But see an intersting effect of the useCapture parameter here (assuming you use Firefox 2 which supports addEventListener()):

<script language="javascript">
if (document.body.addEventListener)
{
document.body.addEventListener("click",
function(){alert("body clicked");}, true); document.getElementById("form").addEventListener("click",
function(){alert("form clicked");}, true); document.getElementById("button").addEventListener("click",
function(){alert("button clicked");}, true); } </script>

Try the example.

<script language="javascript">
document.body.addEventListener("click",
function(){alert("body clicked");}, false); document.getElementById("form").addEventListener("click",
function(){alert("form clicked");}, false); document.getElementById("button").addEventListener("click",
function(){alert("button clicked");}, false); </script>

Try the example .

In the first example, the event are received in the following order: body, form, then button. In the second example, they are in opposite order: button, form, body. Do you see why this is from examining the direction of the captuing and bubbling phase?