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.
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 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.
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.
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.
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.
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:
return false
from the event handling script, the
default action (following
the link, submitting the form) is prevented. This technique was standardized by Netscape 2 and
still works fine.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.
If you wish to go through all event pages in order, you should now continue with the events page.
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.
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.
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.
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)
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.
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(); }
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.