getElementsByTagNames()

One of my fondest W3C DOM wishes is a getElementsByTagNames() method (note the plural "names") that returns elements with several tag names in the order they appear in the document. This is extremely useful in for instance my ToC script which needs all h3s and h4s in the order they appear in the source code.

When I discovered the compareDocumentPosition() method in Level 3 Core, I could finally write a custom script that works in most browsers.

Therefore I now proudly present my new getElementsByTagNames() script. It requires either sourceIndex or compareDocumentPosition to work fully, and since Safari 1.3.2 supports neither the script doesn't sort the elements in this browser.

This is the blog of Peter-Paul Koch, mobile platform strategist, consultant, and trainer. You can also follow him on Twitter.
Atom RSS

I’m around at the following conferences:

(Data from Lanyrd)

Categories:

Monthlies:

Comments

Comments are closed.

1 Posted by Richard York on 30 January 2006 | Permalink

Why not use something like Dean Edwards's cssQuery()? Not only can you get multiple elements by tag name, but I find using css selectors in JS to be much more useful.

2 Posted by Robert Nyman on 30 January 2006 | Permalink

I see it as useful if you want to avoid classes on a lot of elements that you're looking for. Otherwise, my http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/ or http://www.robertnyman.com/2006/01/23/monday-code-giveaway-getelementsbyattribute/ are as useful.

3 Posted by courtenay on 1 February 2006 | Permalink

This requires a few helpers from prototype.js; $A and 'each', which is just a simple iterator; and 'bind' (which uses apply). Sorry for the formatting, it's your comments.

Object.prototype.getElementsByTagNames = function() {
var ret = $A(new Array());
var tags = $A((arguments.length == 1 && arguments[0].constructor == Array) ? arguments[0] : arguments)
tags.each( function(tag,j) {
$A(this.getElementsByTagName(tag)).each (function(iter) { ret.push(iter); }
);
}.bind(this));
return ret;

works like
somenode.getElementsByTagNames('A','div');
somenode.getElementsByTagNames(['a','div']);

4 Posted by Theodor Zoulias on 2 February 2006 | Permalink

Nice! Sorting a big result array has some performance implications though. Opera's implementation for sourceIndex is very slow. A quick test reveals that a more trivial implementation of getElementsByTagNames may be preferable, if the expected result array contains more than 10% of all document elements.

http://users.freestuff.gr/skeftomilos/demos/get-elements-by-tag-names/get-elements-by-tag-names-test.htm

5 Posted by Howard on 8 February 2006 | Permalink

Building collections can be expensive; if your list of tags is longish,
it's likely to be more efficient to simply get *all* elements and then
just select the ones you want from it. Doing it that way also removes
the need to sort: they'll already be in order.

(No error checking; untested):

function getElementsByTagNames(list,obj) {
var tags = {}, i, result = [], elms;
obj = obj || document;
var tags = {};
for (var i=0; i<list.length; i++)
tags[list[i].toUpperCase()] = true;
elms = obj.getElementsByTagName('*');
for (i=0; i<elms.length; i++)
if (elms[i].tagName in tags) result.push(elms[i]);
return result;
}


then ...

var element = document.getElementById('test');
var formFieldList = getElementsByTagNames(['input','select','textarea'],element);