[ Team LiB ] Previous Section Next Section

9.1 Equalizing the IE and W3C Event Models

NN 4, IE 4

9.1.1 Problem

You want a script to inspect details about a particular event when the page is loaded in Internet Explorer and in a W3C DOM browser that supports only the W3C DOM event model.

9.1.2 Solution

Because Internet Explorer (at least through Version 6 in Windows and 5.x in Macintosh) does not implement the W3C DOM event model, and because pure W3C DOM browsers such as Netscape 6 and later implement only the W3C DOM event model, you must use model-specific ways to derive a common reference to the event to assist further processing.

Event handlers receive a reference to the W3C DOM event object as a parameter (see Discussion), whereas the IE event object is a property of the window object. To accommodate both and end up with a single reference that subsequent statements can use to examine the event object, use the following skeletal structure in every event-invoked function:

function functionName(evt) {
    evt = (evt) ? evt : ((window.event) ? event : null);
    if (evt) {
        // perform processing here
    }
}

This structure uses object detection, rather than browser version sniffing, to not only extract the event model-specific reference, but also guard against script errors if the browser does not support either event model (i.e., much older browsers responding to simple events).

9.1.3 Discussion

Getting a non-IE event model browser to pass the event object to the event handler function requires either a little planning ahead or none whatsoever, depending on the way you bind your event handlers to element objects. The W3C DOM specification formally supports event binding only via the addEventListener( ) method of any element, as in the following example:

document.getElementById("myButton").addEventListener("click", processClick, false);

This method was developed for the W3C DOM and found its first implementation in Netscape 6. A function triggered by an event bound to the element in this fashion automatically passes the event object as the sole parameter to the function. All you need to do is catch the parameter by assigning a function parameter variable at the start of the function definition (i.e., the evt inside parentheses in the skeletal structure shown in the Solution).

Fortunately for cross-platform developers, two pre-W3C DOM ways of binding events to elements work without a problem in Netscape 6 and later�and will likely do so for a long time to come. Those two approaches are assigned as element object properties, and assigned the original way, as attributes inside the element's tag.

Assigning an event as a property of an object is performed in one JavaScript statement. The left side of the statement is a reference to the element object and a property consisting of the event handler name (with the "on" prefix) in lowercase letters; the right side is a reference to the function to be invoked when that element receives the event. A function reference is just the function's name without parentheses, as in:

document.getElementById("myButton").onclick = processClick;

Events bound this way in browsers such as Mozilla (and even back to Navigator 4) automatically pass the event object as the sole parameter to the function.

The other cross-platform event binding mechanism is through an attribute embedded in the element's tag. You see a lot of this in code around the Internet because it was the original way event binding took place when scripting started. It is also a convenient way to pass one or more parameters of your choosing to the function. Therefore, it's common to see input form controls pass a reference to the element itself (this) or the containing form element (this.form) to make it easier for the function to work directly with the element's value or other controls in the form. But to convey the W3C DOM event object to the handler function, events bound this way must also explicitly include the keyword event as one of the parameters:

<input type="button" name="myButton" id="myButton" value="Process" 
onclick="processClick(event)" />

You can pass multiple parameters if you like, but the position of the parameters being passed must be the same in the parameter variable definitions in the function. For example, the event handler defined as:

onclick="processClick(this.form, event)"

must have a function defined with two parameter variables to catch the passed arguments:

function processClick(form, evt) {...}

When you include the explicit event object as a parameter, IE also passes its version of the event object, so the syntax does double duty. But the trend in scripting and document markup in general is to get away from this in-tag event binding and gravitate toward other approaches�all in the name of separating content from style and processing.

Binding events by a process other than in-tag attributes, however, has its own gotchas to be aware of. The most significant is that you cannot simply bind events to objects while the page loads but before the objects are loaded into the browser. The JavaScript interpreter attempts to resolve all assignment statements when they execute. If the object is not yet known to the object model, the assignment fails (with a script error). This goes even for the body element: assigning an event handler property to document.body in the head portion of the document triggers script errors in some browsers.

To work around this conundrum, you can place (almost) all of your event assignments in a function that gets invoked after the entire page has loaded. See Recipe 9.2 for more details.

If you use the event object equalization routine shown in the Solution, you may still have to perform additional platform-specific equalizations in your handler function. This occurs whenever the property you're looking for is known by different names (see Recipe 9.3 and Recipe 9.6 for examples). But there is also a sufficient amount of similarity between the two objects' properties that they are quite useful blended into a single event handler function.

9.1.4 See Also

Table 9-3 in the introduction of this chapter for a comparative list of event object properties; all other recipes throughout this book that process events using the event object equalization technique shown here; Recipe 9.2 for triggering a function (for event handler property assignments) after the page loads; Recipe 9.3 and Recipe 9.6 for equalizing disparate event object properties.

    [ Team LiB ] Previous Section Next Section