Bug? IE, getElementsByClassName and "length"

151 views
Skip to first unread message

Josh on Rails

unread,
Nov 3, 2006, 11:38:38 AM11/3/06
to Ruby on Rails: Spinoffs
So, I have this form/datagrid thing. I want to have a button that
clears the fields (not a reset, which would set them to the default
state, I want them blank.) For various reasons, getByClassName seemed
the best way to deal with this.

Everything was fine on Moz/Firefox. Safari seems fine. But IE...

Some detective work later, it seems that the problem is caused by
*another* field on the page. (With it, problems; without it, no
problems.) More detective work suggests that the problem is the field's
name ("length").

More precisely, it seems getElementsByClassName in IE (6 and 7, at
least) will fail to gather elements (returns zero-length array) if
there is an input on the page with 'name="length"'.

Solutions: Change the name of the input, or use the optional parent
argument to avoid it.

More: Looking at the getElementsByClassName declaration in
prototype.js, I'd guess this is really a problem with $A or
getElementsByTagName, but that's as far as I got.

Demo: http://www.thewehners.net/joshua/test_ie_length.html

Christophe Porteneuve

unread,
Nov 3, 2006, 12:01:55 PM11/3/06
to rubyonrail...@googlegroups.com
Hey Josh,

Josh on Rails a écrit :


> More: Looking at the getElementsByClassName declaration in
> prototype.js, I'd guess this is really a problem with $A or
> getElementsByTagName, but that's as far as I got.

Hey there. Yes, this is IE only, and the reason is that IE provides a
"dot-id" child access:

x.childIdOrName

provides access to a child node of x whose id (or name, a more general
issue with IE) is "childIdOrName").

The problem is that IE does that BEFORE resolving property names. So
when you have a HTMLCollection (as is returned by getElementsByTagName)
with a item(...) method and a lenth property (as per DOM Level 2 HTML),
and one of the items is id'd or named "item" or "length", IE freaks out.

Just another consequence of IE's shabby DOM implementation and standards
compliance.

The solution lies indeed where you put it: either change the field's
name (and ID, if need be), or use the scope feature with the parent option.

This post just so you get what the actual problem is...

--
Christophe Porteneuve aka TDD
t...@tddsworld.com

Josh on Rails

unread,
Nov 3, 2006, 1:39:13 PM11/3/06
to Ruby on Rails: Spinoffs
Thanks, Chris. Hopefully, this will save someone else some stress down
the road.

Fred

unread,
Nov 5, 2006, 7:29:58 PM11/5/06
to Ruby on Rails: Spinoffs

Christophe Porteneuve wrote:

> Hey Josh,
>
> Josh on Rails a écrit :
> > More: Looking at the getElementsByClassName declaration in
> > prototype.js, I'd guess this is really a problem with $A or
> > getElementsByTagName, but that's as far as I got.
>
> Hey there. Yes, this is IE only, and the reason is that IE provides a
> "dot-id" child access:
>
> x.childIdOrName
>
> provides access to a child node of x whose id (or name, a more general
> issue with IE) is "childIdOrName").
>
> The problem is that IE does that BEFORE resolving property names. So
> when you have a HTMLCollection (as is returned by getElementsByTagName)
> with a item(...) method and a lenth property (as per DOM Level 2 HTML),
> and one of the items is id'd or named "item" or "length", IE freaks out.
>
> Just another consequence of IE's shabby DOM implementation and standards
> compliance.

I think it's fair to call it a bad idea as it has some unexpected
consequences, but it is entirely due to IE's implementation of the DOM
and the way it resolves identifiers, it has nothing to do with (W3C)
standards compliance /per se/.


> The solution lies indeed where you put it: either change the field's
> name (and ID, if need be), or use the scope feature with the parent option.

Or modify document.getElementsByClassName(). The following function
runs 3 times faster in Firefox and 20 times faster in IE, it doesn't
have any problem with names or IDs of elements (lightly tested, more is
required):

document.getElementsByClassName = function(className, parentElement) {
if (typeof parentElement == 'string'){
parentElement = document.getElementById(parentElement);
} else if (typeof parentElement != 'object' ||
typeof parentElement.tagName != 'string'){
parentElement = document.body;
}
var children = parentElement.getElementsByTagName('*');
var re = new RegExp('\\b' + className + '\\b');
var el, elements = [];
var i = 0;
while ( (el = children[i++]) ){
if ( el.className && re.test(el.className)){
elements.push(el);
}
}
return elements;
}


If the initial identifier resolution is put into the $() function,
prototype will benefit in general.


--
Fred

Fred

unread,
Nov 5, 2006, 9:47:36 PM11/5/06
to Ruby on Rails: Spinoffs

Fred wrote:

> Christophe Porteneuve wrote:
[...]


> > Just another consequence of IE's shabby DOM implementation and standards
> > compliance.
>
> I think it's fair to call it a bad idea as it has some unexpected
> consequences, but it is entirely due to IE's implementation of the DOM
> and the way it resolves identifiers, it has nothing to do with (W3C)
> standards compliance /per se/.

That may need a little more explanation: IE does not distinguish
between ID and name attributes when using getElementById, it treats
them all as IDs. Given:

<div><input name="sally"></div>
<div id="sally"></div>


Then in IE, document.getElementById('sally') will return a reference to
the input, not the div.

[...]


> document.getElementsByClassName = function(className, parentElement) {
> if (typeof parentElement == 'string'){
> parentElement = document.getElementById(parentElement);
> } else if (typeof parentElement != 'object' ||
> typeof parentElement.tagName != 'string'){
> parentElement = document.body;
> }

[...]


> If the initial identifier resolution is put into the $() function,
> prototype will benefit in general.

No, it wont.


--
Fred

Reply all
Reply to author
Forward
0 new messages