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.
|