IE, event objects, and attachEvent()

| 12 Comments

In the 5th edition of my JavaScript book, I wrote:

Although the IE event model provides event details in an Event object, it never passes Event objects as arguments to event handlers.

I don't know how I know this: it is just one of those things I've always known about IE. But a reader (Tom Stambaugh of zeetix.com) just emailed me with a trivially simple counter example. It turns out that if you use attachEvent() (at least in IE 6) then the event handler you specify is passed an event object as an argument.

I don't think I'm the only one who believed that handlers registered with attachEvent() don't get passed an event object. For example, the documentation on attachEvent() at about.com says:

Also unlike the standard DOM method, the event is not passed to the function as a parameter. Instead IE supplies a standard window.event object to hold the details relating to the latest event.

And the documentation for the YUI event library advertises, as a feature of the library, that:

The first parameter your callback receives when the event fires is always the actual event object. There is no need to look at window.event.

The documentation at MSDN is not helpful. It does not say whether or not an event object is passed and the examples it lists don't use any event details.

Does anyone out there know what is up here? Has attachEvent() always caused an event object to be passed to the handler, or is this something that changed in IE 5.5 or IE 6? I don't have an old version of IE I can test this against. I recognize that with the release of IE 7 we may all have better things to do than fire up IE 5, but I'd like to get to the bottom of this!

Update: Thanks to the commenters who have pointed out the interesting fact that the event object passed to a handler is not the same object (not == to) window.event. I've written a trivial test that demonstrates that 1) an object is passed to a handler registered with attachEvent(), 2) that this object is not == to window.event, and that 3) the properties of this object are the same as the properties of window.event (except that they both have a property that refers to different empty arrays).

Note that the test linked to above only runs in IE, so don't bother trying it out in other browsers. If someone has an old version of IE around and is willing to test it, I'd love to hear what you find out. IE 5, IE 5.5, IE 5 on a Mac? Surely this fails on some old version of IE! Otherwise I, and many others, deluded ourselves into thinking that attachEvent was broken in a way that it was not broken.

This winning entry into ppk's addEvent() recoding contest" is another example where the assumption is made that attachEvent() does does not [oops. typo in original post] cause the handler to be invoked with an event object.

Update 2: In comments, Alistair Potts presents test results that indicate that attachEvent has always passed a copy of the window.event object to event handlers. His test code is at: http://www.partyark.co.uk/html/ieeventtest.htm

The next test to undertake will be to determine if setting cancelBubble and returnValue on the event object passed to the handler works the same way as setting them on the global window.event object.

12 Comments

As far as I know nothing changed. The YUI (and other libraries) uses special workaround to fix this problem (and problem with function's scope).

Could you show this example?

David,

Here is what I had always understood about this.

If you wire up an event using the older, DOM-Level 0 event hook up, then you don't automatically get an event object passed into your handler.

For example:

<button id = "btn1" onclick = "test()">Test<button>

function test(e)
{
alert(e.srcElement); // no good, e will be undefined
}

You could of course, explicitly pass in window.event in your inline call:

<button id = "btn1" onclick = "test(window.event)">Test<button>

However, if you use the more modern event style hook up,

document.getElementById('btn1').attachEvent('onclick', test);

function test(e)
{
alert(e.srcElement); // okay
}

Then you should get an event object automatically passed into your handler.

What's more, you can see that e in this case is not the window level event object, because adding a statement like:

alert(e == window.event) yields false.

This was the behavior I expected when I set this sample up (I tested in IE6). To the best of my knowledge, it has always been this way.

I noticed this recently too. I can't test at the moment but IIRC:

function(event) {
alert(window.event==event); // false
};

Can't test at the moment. Will post back later.

Elus: test case is at http://www.davidflanagan.com/attach.html

Stephen: do you have an old version of IE to try this out on?

Dean: thanks for the tip that e != window.event. I've written a test case (see URL above) to demonstrate that e is deep clone of window.event

Thanks to all of you for commenting. Note that I've updated the blog entry itself.

I tried the following in IE5.5, and it worked as expected:

<script type = "text/javascript">
function init()
{
document.getElementById('btn').attachEvent('onclick', function(e)
{
alert(e.srcElement.id + ' was clicked at: ' + e.clientX + ', ' + e.clientY);
});
}
</script>

<body onload = "init()">
<button id = "btn">Click Me</button>
</body>

This test in IE5.5 may not be the greatest though. I'm using the technique some people at Microsoft use to get IE5.5 to run side-by-side with other versions of IE. I don't do this very often, and it's kind of a hack, so even though it appears to be a valid IE5.5 test, I hesitate to say for sure.

Again, I think this might go back to how you wire up the event (DOM Level 0 vs the more modern style). If you do an inline onclick = "myfunc()" it seems that you need to use window.event to get the event ref, as none is passed in for you.

In W3C browsers, you would actually have to explicitly pass in the word event as in: onclick = "myfunc(event)". If I am not mistaken, this is the ONLY time in W3C browser that the static event object is allowed to be referenced in this way.

Stephen,

Thanks for that IE 5.5 test case.

I know (at least I think I know) that event objects are not passed when you register events the traditional way. It is just that many of us seemed also to believe that the same was true when using attachEvent.

In W3C browsers, inline event handers can use the identifier "event" because they get wrapped inside a function which has event as an argument. This is not some special case in which "event" becomes a global as it does in IE. The text of the HTML event handler attribute is transformed into a function which is passed an event object named "event".

David,

That makes sense... I don't claim to be an expert by any means. I just seem to remember reading in one of Danny Goodman's books that "event" is only valid when used inline as I described in my last post, and your explanation as to why this is, helps to clarify that further (at least, helps to clarify it in my previously confused mind).

To get back to the point about attachEvent, it almost looks likes it has always passed in an event object for you (at least in IE5.5+).

I would guess that window.event existed before .attachEvent, and when MS implemented .attachEvent, they decided it made more sense to pass in the event object to the handler? Naturally, the left window.event for DOM-Level 0 event hook ups, so maybe that's why we ended up with both? Not sure.

Interesting to note that atttachEvent doesnt work for all valid events either. For example to set and error handler you have to do it explicitly window.onerror = func;

Some testing using 'trivial test' with Stephen's extra alert wrapped in a strict-mode doctype at http://www.partyark.co.uk/html/ieeventtest.htm

Win 98 // IE 5.0
Win 98 // IE 5.5
Win 98 // IE 6.0
Win XP // IE 7.0

Identical results! Well shiver-my-timbers.

Mac IE5 doesn't support attachEvent or addEventListener so it's never going to work. But I gave up supporting this browser earlier this year.

A

David,
Not to nitpick, but, the winning entry into ppk's addEvent() recoding contest does not make the assumption that the event handler will be invoked with the event object. In fact, the code assumes the addEvent() function and DOM node reside within the same window context, resulting in a null argument being delivered to the event handler (in lieu of the actual event object) when the DOM node and addEvent() function reside in different windows.

Joshua, interesting observation regarding atttachEvent and onerror!

Alistair:

Thank you for running these tests!

Joshua: onerror isn't an event handler like the others. Consider the (message, filename, linenumber) arguments that are passed to it. I wouldn't expect it to work even with addEventHandler.

Douglas: that was a typo in my blog post. I meant "does not" but I forgot the "not"! Good point about different windows!

Well... as long as the event object isn't a proper Ecmascript object, it is of no additonal use. It saves you exactly one line of code:

if (!e && window.event) { e = window.event };

Books

Comprehensive coverage of Ruby 1.8 and 1.9

"The New Most Important Ruby Book"
Peter Cooper,
rubyinside.com

Completely updated for Ajax and Web 2.0

"A must-have reference"
Brendan Eich,
creator of JavaScript

The classic Java quick-reference

Advertising

Pages

Hosted By

Powered by Movable Type 4.21-en