If you use a library that mimics classical inheritance into Javascript, like Prototype or Mootools, then you use the new Element() expression aplenty. It feels far nice to do it all in one constructor-like call, then using document.createElement , and then node.setAttribute and so forth a bunch of times. But I'm not going to argue which is more proper. Instead, what I've found is an annoying inconsistency with Internet Explorer 7 (probably 6 as well, but I didn't bother to check the obvious) when specifying the onclick attribute .
First, what I do that causes the problem.
var btn = new Element('a')
And of course, I include an object for the secord parameter that sets all the attributes of the element as well.
var btn = new Element('a',{
'class':'deleteButton',
'href':'/categories/delete',
'text':'Delete',
'onclick':'deleteCat(this); return false'
});
//creates <a href="/categories/delete" class="deleteButton" onclick="deleteCat(this); return false">Delete</a>
As you can see, very useful, very logical, very easy.
I did exactly this when you clicked on a New Category button; a little modal box showed up, you type in the name, and then the new category shows up in the list. And all categories have a button to delete said category. Since this was a new element in the DOM, any event listeners on deleteButtons wouldn't register for this new one.
There are three ways of handling this: one being to create a new event listener for each new button as it's created, two is to use event delegation and listen instead on a higher element for events on anchor tags, or three to specify an onclick function. I opted for the third option, regardless of which is best , because in my situation, all were equal in accessibility (my application requires Javascript), but the third is easiest. It seemed.
As Expected
Firefox did exactly what I wanted. New button, when clicked fires its onclick function. And, as should be expected, Internet Explorer did not. After the mandatory cursing ritual , I opened IE Developer Toolbar and inspected the newly created button. Of course, Mootools hadn't let me down. The element indeed had the onclick attribute, properly set to the function I wanted.
Curious if it was the way Mootools created the Element that broke it, I used the DOM methods in a test, first createElement('a'), then setAttribute('onclick','doStuff(this); return false'), and, look! Still broken .
This tells me then that Internet Explorer does not pay attention to onEvent attributes after the first DOM initialization . Now, messing with that attribute does nothing. It doesn't set an actual event listener, so instead you must do so specifically on the Element in the Javascript. Here's the final mess:
var dButton = new Element('a',{'class':'deleteButton',href:'/categories/delete',onclick:'deleteCat(this); return false',title:'Delete Category'});
//ie7 sucks
dButton.onclick = function() { deleteCat(this); return false; };
Should this be in the framework?
In retrospect, should fixing this be always up to myself everytime I do something similar, keeping IE's faults in mind? Or should the library I'm using (Prototype, Mootools) have this in mind in it's Element() function?
The function could have added to a check for the Trident engine, and if true, check for onEvent attributes. If true, set those attributes explicitly.
Seems like the better solution, so a developer can write a command and expect it to work cross-browser . Do you agree?

This is not the appropriate way to attach events with MooTools. you should instead do:
var btn = new Element('a',{ 'class':'deleteButton', 'href':'/categories/delete', 'text':'Delete', events: { click: function() { deleteCat(this); return false; } } });Attaching events this way allows MooTools to prevent memory leaks and provide you with other more useful things (like a unified event object).
Good point Aaron. I had forgotten about Mootools way of attaching event listeners at construction. I had actually faced this problem in Prototype first, since we use Prototype at my day job.
Although, my point is still true. Simply assigned the attribute of onclick does not work in Internet Explorer. I'd run into the bug before when trying to change the onsubmit attribute of a form, depending on the information so far entered. The bug in IE is writing to the attribute does not assign a listener.
Excellent! I was looking for a solution for this,
and your post was the only place that explained it clearly enough.
This works:
var appendEvent = function () { if (window.addEventListener) { return function (el, type, fn) { if (typeof el === 'string') { document.getElementById(el).addEventListener(type, fn, false); } else { el.addEventListener(type, fn, false); } }; } else if (window.attachEvent) { return function (el, type, fn) { var f = function () { fn.call(((typeof el === 'string')?document.getElementById(el):el), window.event); }; if (typeof el === 'string') { document.getElementById(el).attachEvent('on' + type, f); } else { el.attachEvent('on' + type, f); } }; } }(); //Append the event: (omit 'on' in change) appendEvent('element','change', function () {alert('Hello World')});@Kim: Yes... that does work. Thought I wasn't commenting on a cross-browser way of creating events. If I'm using Mootools (or Prototype), it's already provided for me.
I think I have a generic solution for Mootools
but then also have
'events' : { 'click' : function() { eval(this.onclick); } }this will work as long as you don't have a return statement or similiar in the onclick, such as
Thanks for the clear write-up Sean. I'm new to Prototype and was having fun--it's amazing how quick you can build stuff--until I thought "oh time to try it in IE".
Placing the function call with "href=javascript: func();" worked, but I like this way better.
I'm surprised that the framework doesn't check for this. Maybe it's just not possible to initialize an element and simultaneously mangle its events.