Closed Bug 14869 Opened 25 years ago Closed 12 years ago

getElementsByTagName() returns HTMLCollection instead of NodeList

Categories

(Core :: DOM: Core & HTML, defect)

defect
Not set
normal

Tracking

()

RESOLVED WONTFIX

People

(Reporter: ckritzer, Unassigned)

References

Details

(Keywords: helpwanted)

Attachments

(3 files, 1 obsolete file)

Overview Description: the getElementsByTagName() function is returning an
HTMLCollection instead of a NodeList.  According to the spec, it should be
returning a NodeList.

Steps to Reproduce:
1) Load the following html into the browser:
*****************************************************************************

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML>
	<HEAD>
		<TITLE>test.html</TITLE>
	</HEAD>
	<BODY>
		<SCRIPT type="text/javascript">
			document.write("<p>");
			document.write("<b>childNodes</b> should return a <b>NodeList</b><br>");
			document.write("<b>Expected Results:</b> document.firstChild.childNodes =
[object NodeList]<br>");
			document.write("<b>Actual Results:</b> document.firstChild.childNodes = " +
document.firstChild.childNodes + "<br>");
			document.write("<hr>");
			document.write("<b>getElementsByTagName</b> should return a
<b>NodeList</b><br>");
			document.write("<b>Expected Results:</b>
document.firstChild.getElementsByTagName('*') = [object NodeList]<br>");
			document.write("<b>Actual Results:</b>
document.firstChild.getElementsByTagName('*') = " +
document.firstChild.getElementsByTagName('*') + "<br>");
		</SCRIPT>
	</BODY>
</HTML>


*****************************************************************************
2) Read the printout


Actual Results: [object HTMLCollection]


Expected Results: [object NodeList]


Build Date & Platform Bug Found:
1999092408MacOS86
1999092408Win98
1999092408Linux6

Additional Builds and Platforms Tested On:


Additional Information:
QA Contact: gerardok → ckritzer
Summary: getElementsByTagName() returns HTMLCollection instead of NodeList → getElementsByTagName() returns HTMLCollection instead of NodeList
Status: NEW → RESOLVED
Closed: 25 years ago
Resolution: --- → WONTFIX
This does the right thing in the C++ interface. The methods of NodeList are a
subset of the methods of HTMLCollection, so the script user shouldn't see any
difference. Marking WONTFIX for this release.
Status: RESOLVED → VERIFIED
Marking VERIFED WONTFIX for this release per vidur's comments.
Well, Vidur was wrong. I noticed today. :)

If I add a method to the NodeList prototype, I should be able to call that
method on the result of getElementsByTagName:

NodeList.prototype.test = function() { alert("test"); }
document.getElementsByTagName('*').test();

This works in Opera.
Status: VERIFIED → REOPENED
Resolution: WONTFIX → ---
Assignee: vidur → general
Status: REOPENED → NEW
QA Contact: ckritzer → ian
This bug is fixed. Here's the results I get with a recent firefox nightly (20050622)

childNodes should return a NodeList
Expected Results: document.firstChild.childNodes = [object NodeList]
Actual Results: document.firstChild.childNodes = [object NodeList]
getElementsByTagName should return a NodeList
Expected Results: document.firstChild.getElementsByTagName('*') = [object NodeList]
Status: NEW → RESOLVED
Closed: 25 years ago19 years ago
Resolution: --- → FIXED
This is not fixed. getElementsByTagName still returns [object HTMLCollection].
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
See bug 162927 and bug 143191.
Severity: major → normal
Keywords: helpwanted
Priority: P3 → --
Ah, yes, the getElementsByTagName result does indeed return true when doing
instanceof NodeList. 

Then adding methods to NodeList.prototype should work right? Maybe my only
problem is bug 300519.
*** Bug 312427 has been marked as a duplicate of this bug. ***
How does this differ from bug 162927?  The summaries are almost identical.
I have this problem using prtototype.js framework

...
<tr id="tr_1">
<form id="frm_1" name="frm_1">
  <input type="hidden" value="x" id="x" name="x">
  <td>  <input type="text" id="y" name="x"></td>
  <td>  <input type="text" id="z" name="z"></td>
</form>
</tr>
<tr id="tr_2">
<form id="frm_2" name="frm_2">
  <input type="hidden" value="x" id="x" name="x">
  <td>  <input type="text" id="y" name="x"></td>
  <td>  <input type="text" id="z" name="z"></td>
</form>
</tr>
<tr id="tr_3">
<form id="frm_3" name="frm_3">
  <input type="hidden" value="x" id="x" name="x">
  <td>  <input type="text" id="y" name="x"></td>
  <td>  <input type="text" id="z" name="z"></td>
</form>
</tr>
...

(Removed not important code from original.)

I use this javascript:


modify = function(id){
//id is a number
...
  var myform = $('frm_' + id);
  var param = myfrom.serialize();
...
}

The problems:
- myform return HTMLCollention instead nodeList
- param return nothing

Cheking prootype.js look what use getElementsbyTagName('*') for collect elements .
I have another code what work fine, the only diference is what i have ONE form

I use Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0


Well, i found the bug in my code

i have before:
...
<tr id="tr_1">
<form id="frm_1" name="frm_1">
  <input type="hidden" value="x" id="x" name="x">
  <td>  <input type="text" id="y" name="x"></td>
  <td>  <input type="text" id="z" name="z"></td>
</form>
</tr>
<tr id="tr_2">
<form id="frm_2" name="frm_2">
  <input type="hidden" value="x" id="x" name="x">
  <td>  <input type="text" id="y" name="x"></td>
  <td>  <input type="text" id="z" name="z"></td>
</form>
</tr>
<tr id="tr_3">
<form id="frm_3" name="frm_3">
  <input type="hidden" value="x" id="x" name="x">
  <td>  <input type="text" id="y" name="x"></td>
  <td>  <input type="text" id="z" name="z"></td>
</form>
</tr>
...

Checking with DOM Inspector the tree see that:
HTML
  BODY
    DIV
      TABLE
        form
        tr
          td
            input
          td
            input
          td
            input
        form
        tr
          td
            input
          td
            input
          td
            input
...

How can you see , the form element NOT have childrens, so i change code (only posted in DOM Tree):
html
  body
    div
      table
        tr
          td
            form
              table
                tr
                  td
                    input
                  td
                    input
                  td
                    input
        tr
          td
            form
              table
                tr
                  td
                    input
                  td
                    input
                  td
                    input
...

This way myform.getElementaByTagName('*') return HTMLCollention (thats is correct, i know now) and "var param = myfrom.serialize();" return form fields

Maybe this is not bug from DOM, only a bad page desing
The last two comments sound like bug 265976.  Do they have anything to do with this bug?
GetElementsByTagName or GetElementsByClassName etc. slows FF down considerably, to have a more flexible working and faster (page) loading save the following file as SelectableElementsTable.js inside the components folder of your browser.
The download link for my javascript file is here:
http://www.4shared.com/file/18447141/4fd08f46/SelectableElementsTable.html
File size: 10835 bytes
MD5: 405c4b524f49c958c285bff1c58944c3
SHA1: c2cc25768d16a02d4db8b02e12cab4ae5dec5085

I got various reports that attest that the script makes the browser load pages considerably faster. But I like to get back info from you if this could be brought in. Somebody take to test this?
Polonus, could you file a new bug on that and attach the javascript file to the bug? Thanks.
Hello all,

Is this bug still occuring, happening... or should it be resolved as a DUPLICATE of bug 162927 ? 

Thank you, Gérard
Assignee: general → nobody
QA Contact: ian → general
I confirm it is still occuring on FF 3.5. I've written another test : 
*********************************************************
<!DOCTYPE html>
<html>
  <head>
    <title>document.getElementsByTagName misbehavior</title>
  </head>
  
  <body>
     <script type="text/javascript">
          document.write("Object.prototype.toString.call(document.getElementsByTagName('*')) : ");
          document.write("<b>" + Object.prototype.toString.call(document.getElementsByTagName('*')) + "</b>");
          document.write("<br>(<b>[object NodeList]</b> expected)");
     </script>
  </body>
</html>
*********************************************************
The test in comment 16 is just looking at what toString returns.  That's not that important (and in particular the spec does NOT define what toString should be).  The real question is whether instanceof NodeList tests true (it used to, but doesn't seem to anymore; someone should figure out when that stopped working) and whether extending NodeList.prototype makes things show up on the object (but this is generally broken in Gecko).
It's still happening, Firefox 12 nightly.. I'm determined to fix this. My test case will be http://jsfiddle.net/DRRcX/8/.
(In reply to Corey Richardson from comment #20)
> It's still happening, Firefox 12 nightly.. I'm determined to fix this. My
> test case will be http://jsfiddle.net/DRRcX/8/.
It's likely to be enough, but why not using the test cases attached above?
Anyway, good luck, I'm looking forward to seeing this one fixed :-)
Good progress made, I think I have a fix, now just to build and test :)
Attached patch Broken patch (obsolete) — Splinter Review
This patch does NOT work! It is simply here for posterity (and ease of reference). Tried to implement some advice from bz, didn't go too well.
You forgot to set mExposed in nsContentList::nsContentList. See if that helps!
Thanks for catching that, a silly oversight. It should work now, my own testcase I can't confirm because, well, tip won't run jsfiddle. I used the test case from 16 instead. What's next?
Attachment #589323 - Attachment is obsolete: true
Some combination of asking for review and running the test suite.  I can push the patch to try for you if you like.

But again, I suspect that not having namedItem on these lists will be a compat problem....
The |make check| passed, but there were 14 failures for |make xpcshell-test|. Currently building a clean source tree to see if my patch affected that number. I really hope no sites depend on behaviour that shouldn't exist... I am using tip of mozilla-beta, btw.
> The |make check| passed, but there were 14 failures for |make xpcshell-test|.

You'll also need to run mochitest (regular, chrome, browser-chrome) and reftest.... It's easier to just push to try once you have a patch you're happy with.

> I really hope no sites depend on behaviour that shouldn't exist...

Sites depend on things like that all the time.  I'll be extremely shocked if the patch as-is doesn't break some sites.
(In reply to Boris Zbarsky (:bz) from comment #28)
> > The |make check| passed, but there were 14 failures for |make xpcshell-test|.
> 
> You'll also need to run mochitest (regular, chrome, browser-chrome) and
> reftest.... It's easier to just push to try once you have a patch you're
> happy with.
> 

Please and thank you :)

> > I really hope no sites depend on behaviour that shouldn't exist...
> 
> Sites depend on things like that all the time.  I'll be extremely shocked if
> the patch as-is doesn't break some sites.

Sure. But the MDN says it returns a NodeList. The spec says it returns a
NodeList. When you don't follow the spec, how can you expect breakages not to
occur? How can we claim to render in standards mode with inconsistencies like
this... not saying the spec is perfect, but it should at least be followed. Maybe that's just me, though :\
Chrome (and presumably all webkit) and Opera have the correct behavior. It's just FF and IE that do it wrong.
> how can you expect breakages not to occur?

Authors don't read the spec.  Or MDN, mostly.  They just copy/paste whatever works.

> not saying the spec is perfect, but it should at least be followed.

Or, in this case, changed, because there's no good reason for it to be the way it is other than internal W3C politics from 10 years ago.  See http://lists.w3.org/Archives/Public/www-dom/2012JanMar/0007.html

> and Opera

Opera has a non-spec namedItem method on all NodeLists.  It's only WebKit that doesn't have a namedItem on the return value of getElementsByTagName.  I wouldn't mind the change if we had a namedItem on NodeList, but of course then you have to implement it on stuff like childNodes and so forth... and it's still not following the current spec.

I pushed the patch to try.  https://tbpl.mozilla.org/?tree=Try&rev=122abba4c7f2
(In reply to Boris Zbarsky (:bz) from comment #31)
> > how can you expect breakages not to occur?
> 
> Authors don't read the spec.  Or MDN, mostly.  They just copy/paste whatever
> works.
> 

Sad that that's what it has come to. 

> > not saying the spec is perfect, but it should at least be followed.
> 
> Or, in this case, changed, because there's no good reason for it to be the
> way it is other than internal W3C politics from 10 years ago.  See
> http://lists.w3.org/Archives/Public/www-dom/2012JanMar/0007.html
> 

Changing the spec is even better if the spec no longer makes sense. Do you think the change is likely?

> > and Opera
> 
> Opera has a non-spec namedItem method on all NodeLists. 

Fair enough.

Changing the spec does make the most sense to me, I still can't really figure out why NodeList and HTMLCollection both exist. 

In any case, this has served as a good ice breaker, I think I might get more involved in the project somehow.
> Sad that that's what it has come to. 

That's how HTML has pretty much always worked.  That's why it was successful.  ;)

> Do you think the change is likely?

I don't know.

> I still can't really figure out why NodeList and HTMLCollection both exist. 

Because HTMLCollection was defined in the "DOM HTML" specification but there were methods in the "DOM Core" specification that wanted to return nodelists.... but couldn't return HTMLCollection, because it was in a different specification.

Like I said, politics.  From 10 years ago.
Keywords: dev-doc-needed
(In reply to Boris Zbarsky (:bz) from comment #31)
> (...)
> It's only WebKit
> that doesn't have a namedItem on the return value of getElementsByTagName.
If it's the case since the beginning of Webkit, then it means that no compatibility issues have been found since the introduction of Safari and Chrome in the market (otherwise, they would have added the namedItem method).

I think I recently saw a study of which property names were used in on* attributes (was it by you?). If there is such a tool around, could it be run to see whether "namedItem" is actually used on the web.
https://tbpl.mozilla.org/?tree=Try&rev=122abba4c7f2

Something doesn't look happy here.

(In reply to David Bruant from comment #34)
> I think I recently saw a study of which property names were used in on*
> attributes (was it by you?). If there is such a tool around, could it be run
> to see whether "namedItem" is actually used on the web.

Note that this also affects list.foo and list["foo"], which are rather harder to look for.
(In reply to Ms2ger from comment #35)
> (In reply to David Bruant from comment #34)
> > I think I recently saw a study of which property names were used in on*
> > attributes (was it by you?). If there is such a tool around, could it be run
> > to see whether "namedItem" is actually used on the web.
> 
> Note that this also affects list.foo and list["foo"], which are rather
> harder to look for.
oh ok. I didn't know that. It indeed makes things much harder.
Try run for 122abba4c7f2 is complete.
Detailed breakdown of the results available here:
    https://tbpl.mozilla.org/?tree=Try&rev=122abba4c7f2
Results (out of 215 total builds):
    exception: 6
    success: 21
    warnings: 175
    failure: 13
Builds (or logs if builds failed) available at:
http://ftp.mozilla.org/pub/mozilla.org/firefox/try-builds/bzbarsky@mozilla.com-122abba4c7f2
https://tbpl.mozilla.org/?tree=Try&rev=122abba4c7f2

Anyone else get a "Loading failed: error"?
> then it means that no compatibility issues have been found since the introduction of
> Safari and Chrome in the market

Depending on browser-sniffing that's even possible.

> could it be run to see whether "namedItem" is actually used on the web.

namedItem is used all over the place on the web.  Unlike the on* analysis, which was simple syntax, for purposes of this bug one would have to figure out what sort of object |x| is given the JS "x.namedItem('foo')".  Specifically whether x is document.forms or document.all or something (which have a namedItem per spec) or a document.getElementsByTagName() (which does not).

I just looked through some Google code search results for namedItem, btw, and I see this pattern pop up a few times:

  (document.all || document.getElementsByTagName("*")).namedItem(something)

This works in all non-WebKit browsers; fails in WebKit.

Ms2ger, good point about name lookups!  I hadn't even thought about those.  A simple test shows that both WebKit and Opera support them on the return value of getElementsByTagName.  Of course so do IE and Gecko.  So I expect that's required for web compat.  I'll be posting to the DOM mailing list about this; the spec needs to change.

I don't think it's worth worrying about this bug until the spec is fixed, because the changes we need to make strongly depend on how the spec gets fixed.

> Anyone else get a "Loading failed: error"?

Works ok for me....
I've added a note describing the various types returned by this method in different browsers to the MDN article at https://developer.mozilla.org/en/DOM/element.getElementsByTagName
When MDN is less broken I'll add notes to https://developer.mozilla.org/en/DOM/document.getElementsByClassName and the rest of 'em.
I already did that. MDN has issues with displaying articles currently (mostly code samples), but editing works OK.
Why getElementsBy* can't return a NodeList and,  when all nodes are HtmlElement, return a NodeList which is also an HtmlCollection ?
This should match both DOM and HTML DOM specs and the usual practices on web.
"is" in what sense?

The object returned in fact implements both the NodeList and HTMLCollection interfaces.

It obviously can't inherit from both prototypes, since that's not how prototypes work in JavaScript.
Sorry, bad writing.

In sens that NodeList could inherit HtmlCollection (when all his Node are HtmlElement, of course).
There is no multiple inheritance in JavaScript.
Where is the multiple inheritance ?
Object inherits NodeList inherits HtmlCollection. There is only one inheritance for each prototype.
> Object inherits NodeList inherits HtmlCollection

But NodeList doesn't inherit from HTMLCollection; that's the point.
I missed something... NodeList doesn't inherit another prototype ? So why it's not possible for NodeList to inherit the HTMLCollection prototype ?
The spec defines that NodeList.prototype has Object.prototype as its prototype.
Ah... ok, i expected a slightly more technical reason...
I guess it's also true for HTMLCollection ?
> i expected a slightly more technical reason

Like what?  The fact that HTMLCollection has methods that make no sense on a NodeList?
Anything else, but not the spec breaks the inheritance of NodeList and HTMLCollection.

Come to think twice, the spec is for javascript, not for the browser that prepare objects to be exposed. So the browser should not be concerned by the specification and should be able to make inheritance ?
The spec is for what the prototype chain looks like.  How about you actually read the spec involved?  It's a combination of http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html and http://dev.w3.org/2006/webapi/WebIDL/

In any case, the DOM spec editor recently explicitly made getElementsByTagName return HTMLCollection, basically for the reasons listed in comment 39.  Marking wontfix, since we're doing what the spec calls for at this point...
Status: REOPENED → RESOLVED
Closed: 19 years ago12 years ago
Resolution: --- → WONTFIX
I did that, but ... it's a wiki.  What prevented you from updating it yourself?
I don't feel authoritative enough to change such an important page / doc as I do not have the needed knowledge.
(In reply to :aceman from comment #56)
> Can you update
> https://developer.mozilla.org/en-US/docs/DOM/element.getElementsByTagName ?
What change do you wish to see made?
I assume you have an answer, otherwise, you wouldn't be asking ;-)

(In reply to :aceman from comment #58)
> I don't feel authoritative enough to change such an important page / doc as
> I do not have the needed knowledge.
As the DOM topic driver https://developer.mozilla.org/en-US/docs/Project:Topic_drivers (self-proclaimed a minute ago to be fully honest), I grant you the authority to do this change since I assumed above you know which change you want to be seen.

To detail a little more, the doc team really really is understaffed. I'm, myself, just a volunteer contributing on my free time. Be sure of one thing. No one in the doc team will *ever* come at you to say "you don't have the authority, you shouldn't touch that page!". We will largely prefer someone writing content that is half-right and fix it later if needed.
So, I was joking above about "granting" you anything :-) You already have the authority.

For the time being, I encourage you to fix the element.getElementsByTagName page and send me and e-mail or tweet to ask for a review when you feel you're done.
Thanks, but bz already made the needed change.

Actually I wouldn't do the change even with permission, because I don't know what exactly needs to be done. I just see that it mentions NodeList and bz says it is no longer the case. But apart from that there may have been other side-facts which I would not be knowledgeable enough to add.
(In reply to :aceman from comment #60)
> Actually I wouldn't do the change even with permission
You don't need any ;-)

> because I don't know
> what exactly needs to be done. I just see that it mentions NodeList and bz
> says it is no longer the case. But apart from that there may have been other
> side-facts which I would not be knowledgeable enough to add.
It happens to me a lot. I change the doc to the best of my knowledge and then comment on the relevant bug to say it's been documented and limitations/questions I came across and how I solved them.
If people disagree or want to complete, either they ask and explain (which can sometimes be copy/pastable) or do the adjustments themselves.
What I'm doing is far from perfect, but it's always much much better than nothing. I encourage you to adopt the same attitude. If at any point you're in doubt, find people on IRC #devmo or dev-mdc@lists.mozilla.org
Component: DOM → DOM: Core & HTML
You need to log in before you can comment on or make changes to this bug.