Introduction to Events

See section 7A of the book.

Events are supported by all JavaScript browsers except for Explorer 3 on Mac.

Omniweb 4.2 and lower have meager event support.

Events are the beating heart of any JavaScript application. On this page I give an overview of what event handling is, what its problems are and how to write proper cross-browser scripts. I will also provide pages with the gory details of event handling.

Without events there are no scripts. Take a look at any web page with JavaScript in it: in nearly all cases there will be an event that triggers the script. The reason is very simple. JavaScript is meant to add interactivity to your pages: the user does something and the page reacts.

Therefore JavaScript needs a way of detecting user actions so that it knows when to react. It also needs to know which functions to execute, functions that do something that you, the web developer, have judged likely to increase the appeal of your pages. These pages describe the best way to write such scripts. It isn’t easy, but it is very satisfying work.

When the user does something an event takes place. There are also some events that aren’t directly caused by the user: the load event that fires when a page has been loaded, for instance.

JavaScript can detect some of these events. From Netscape 2 onwards it has been possible to attach an event handler to certain HTML elements — mostly links and form fields in the early days. The event handler waits until a certain event, for instance a click on a link, takes place. When it happens it handles the event by executing some JavaScript you have defined.

When the user takes action he causes an event. When your script makes the page react to this event, interactivity is born.

History of event handling

As I said, without event handling there is no point in adding JavaScript to your pages. The best scripts are those that react to something the user does. Therefore, when Netscape released its Version 2 browser which supported JavaScript, it also supported events.

Netscape model

Netscape 2 supported only a few events. Mouseover and mouseout quickly became famous because of the legendary mouseover effect that changed images onMouseOver and changed them back onMouseOut. It was also possible to see if the user submits or resets a form, so that client–side form validation became possible. The browser could also detect if a form field receives or loses the focus or if the page has finished loading or starts unloading. Although by present standards this is very basic behavior, at that time it was a revolutionary extension of the possibilities of Web pages. True interaction became possible because you could react to user actions.

In its most ancient form an event handler looks like this. When the user clicks on this link, the event handler is executed and the alert pops up.

<a href="somewhere.html" onclick="alert('I\'ve been clicked!')">

It is very important to realize that this ancient way of event handling was de facto standardized by Netscape. All other browsers, including Explorer, had to conform to the way Netscape 2 and 3 handled events if they wanted JavaScript to work. Therefore these ancient events and event handlers work in all JavaScript browsers.

Modern event models

However, since the introduction of these simple event handlers much has changed. First of all the number of events has increased. Also, the way of registering event handlers to HTML elements was changed. They can now be set entirely through JavaScript. No more need for huge numbers of event handlers cluttering up your code, now you could write a simple script that sets all event handlers for you.

The Version 4 browsers also provided more information about the event itself. Where was the mouse when the event happened? Was any key pressed? Finally, browser vendors had to decide what happened when an element and its parent element both had a handler for the same event. Which event fires first?

Since this functionality was added at the height of the Browser Wars, Netscape and Microsoft made a distinct point of creating totally incompatible event models. More recently a third model has appeared on the scene when W3C published its DOM Event specification. Despite one serious flaw, W3C’s model, which is loosely based on the old Netscape model but much more generalized and versatile, is an excellent piece of work, adding lots of new interesting functionalities and solving a lot of problems of older event models.

Of course the existence of three models means that event handling doesn’t work the same way in all browsers.

Browser compatibility problems

There we go again. As with DHTML, the W3C DOM or other advanced scripting techniques, we have to take care to execute specific bits of code only in those browsers that understand them. Calling stopPropagation() in Explorer or srcElement in Netscape would give horrid errors and would ensure our script’s uselessness. Therefore we must first check if the browser supports the methods or properties we want to use.

But a simple code branch like

if (Netscape) {
	use Netscape model
}
else if (Explorer) {
	use Microsoft model
}

is only a first approximation of a solution since it leaves out the minor browsers. The most recent ones can handle a fair amount of modern event handling, unless your script in its infinite wisdom decides that the minor browsers should not be allowed to even try to run the code because they are not Netscape or Explorer.

All minor browsers have had the unenviable task of deciding which event model to support. Konqueror/Safari, as always, has opted for strict standard compliance and supports the W3C model. Opera and iCab have been more cautious and support the larger part of both the old Netscape model and the Microsoft model. I haven’t yet studied the minor minor browsers.

But a minor minor browser might support the Microsoft way of accessing an event, while the actual event properties are a mix of the W3C and the old Netscape model. This should be no problem, after all the browser follows well known patterns in its own way. Your scripts should be ready for it.

Don’t use that browser detect

First of all never EVER use a browser detect. This is the fastest way to hell. Any script that uses navigator.userAgent for event model detection is worse than useless and should be laughingly dismissed.

Secondly, don’t confuse DHTML object detection with event object detection. When writing DHTML we commonly check for DOM support by asking, for instance, if (document.all) is supported. If so, a script using the Microsoft all container can safely be executed.

But DHTML and event handling have different browser compatibility patterns. For instance, Opera 6 supports parts of the W3C DOM but not the W3C event model. Therefore DHTML object checking would execute the wrong event code branch in Opera. So scripts using if (document.layers) and such for event model detection are also incorrect.

The right questions

Then what are we to do? The names of the event properties cause the worst problems. If we use a lot of specific object detections in this area, we solve 99% of the browser incompatibilities. Only finding the mouse position, is very hard, accessing other bits of information is simpler.

Furthermore, it is better not to think about three overall event models at all. Instead, we have to understand four event registration models, two event accessing models and two event orders.
See also the quick event compatibility tables for a broad overview of event handling and browser compatibility.

Now this sounds terribly complicated but it isn’t. In fact, when I discovered this I began to truly understand event handling. It’s all about asking the right questions. Don’t ask “How should I write an event handling script?” Though this is a correct question, it is very hard to answer — it’s going to take me eleven long pages. Instead, you should ask more specific questions that have specific answers:

All questions above will be treated on separate pages that give background information and the nuts and bolts of event handling.

The trick of writing cross–browser event handling scripts is not to use an overall event model check but to answer all these questions separately. You’ll find that you need to worry about browser compatibility mainly when reading out event properties.

First choose an event registration model, then make sure the event is accessed by all browsers, then read out the correct properties and then solve event order problems — if any occur. Thus you can solve each compatibility problem separately and ensure your code runs in all browsers that support advanced event handling.

Continue

If you wish to go through all event pages in order, you should now continue with the events page.

Writing an event handling script

So how do you write an event handling script? On this page I give a quick overview for those who need fast answers and want to study the theory later.

Registering an event handler

The first step is registering your event handler. You have to make sure that the browser executes your script whenever the event you’ve chosen takes place.

There are four models for registering event handlers. inline, traditional, W3C and Microsoft.

It’s best to use the traditional model, since it is completely cross–browser compatible and gives much freedom and versatility. To register an event handler, do

element.onclick = doSomething;
if (element.captureEvents) element.captureEvents(Event.CLICK);

Now the function doSomething() is registered as the handler of the click event of HTML element element. This means that whenever the user clicks on the element, doSomething() is executed.

Accessing the event

When you’ve registered your event handler you start writing the actual script. Usually you want to access the event itself, so you can read out information about the event.

To access the event so that you can read out its properties, always start your event handling function thus:

function doSomething(e) {
	if (!e) var e = window.event
	// e refers to the event
}

Now e refers to the event in all browsers and you can access the event.

Accessing the HTML element

Sometimes you also want to access the HTML element the event took place on. There are two ways for doing this: using the this keyword or using the target/srcElement properties.

The safest way to access the HTML element is by using the this keyword. this doesn’t always refer to the correct HTML element, but in combination with the traditional model it works fine.

function doSomething(e) {
	if (!e) var e = window.event
	// e refers to the event
	// this refers to the HTML element which currently handles the event
	// target/srcElement refer to the HTML element the event originally took place on
}

The target/srcElement properties contain a reference to the HTML element the event originally took place on. Very useful, but when the event is captured or bubbles up the target/srcElement doesn’t change: it’s still the element the event originally took place on. (See the Event properties page for target/srcElement, see the this page for the this keyword)

Reading out properties

As to reading out interesting event properties, this is the area with the worst browser incompatibilities. Study the event compatibility tables and write your own script to read out the information you need.

Be sure to always use the most detailed object detection possible. First check if each property exists, then read out its value. For instance:

function doSomething(e) {
	if (!e) var e = window.event
	if (e.keyCode) code = e.keyCode;
	else if (e.which) code = e.which;
}

Now code contains the pressed key in all browsers.

Event order

Finally, you have to decide whether you want the events to bubble up. If you don’t want that to happen, stop the propagation of the event.

function doSomething(e) {
	if (!e) var e = window.event
	// handle event
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
}

Writing the script

Now you can start actually writing the event handling script. Use the information the previous snippets of code give you to decide what actually happened when the event took place and how your script should react to it. Remember: keep the interaction logical or your users won’t understand what’s happening.