Sunday, July 12, 2009

Best practices?: Modifying HTMLCollections in IE

I just ran into a very weird IE quirk, and I'm wondering what the best practice would be regarding it. (I've only tested in IE7; it might show up in other versions.)

Before I had IE installed, I had to modify a form and then find my elements in it to modify them again, and the elements' names were the most convenient way to accomplish the second part. So of course I went for the form.elements collection, and this works fine in Firefox. But not only is this property actually the form itself in IE, the developers apparently didn't read this part of the spec:
http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-1019015399
Note: Collections in the HTML DOM are assumed to be live meaning that they are automatically updated when the underlying document is changed.
To demonstrate what this means, I threw together a small test page (post continues below):
<html>
<head>
<title>IE DOM modifications</title>
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
<script type="text/javascript">
window.onload = function(){
var form = document.forms.namedItem('test');
var input = document.createElement('input');
input.name = 'foo';
input.type = 'hidden';
input.value = 'bar';
form.appendChild(input);
console.log(form.childNodes[0]);
// form[input.name] = input;
console.log(form['foo']);
console.log(form.elements.namedItem('foo'));
};
</script>
</head>
<body>
<form name="test">

</form>
</body>
</html>

If form[input.name] = input; (a very ugly hack) is commented, the first call to console.log works but the other two don't. Otherwise, the first two work but the last still doesn't.

So here's my question: Is this the best way to workaround this quirk? The idea of form elements being direct properties of the form isn't in the standard, and the standard namedItem function remains broken. I managed to still use namedItem by default, but I really don't like the hack at all.

Here's how I retrieved my element:form.elements.namedItem(name) || form[name]