The joy of… JavaScript's getElementsByTagName()
For what it's worth the kernel of this article was dictated into my phone on my drive into work this morning. I got the idea, had the framework and figured- why the hell not just talk to myself for a while. It was actually pretty efficient, so I might do more of it and if I get good enough at this sort of extemporaneous dictation I might turn it into a podcast ![]()
getElementsByTagName is probably my second favorite JavaScript DOM method behind getElementById. By itself getElementsByTagName is very powerful and a combination of the two can create a powerful tool to access DOM elements anonymously. One of the core tenets in my work as a front end developer is to use semantic xHTML markup with no extraneous hooks which I then manipulate with JavaScript. I try for a clear separation between behavior, content and style, so I hate to create classes or IDs just for script. Unless an ID or Class has a real benefit in terms of CSS or has a real, valid descriptive benefit for the document in a semantic sense, I don't want to use anything other than plain vanilla HTML elements. I hate to add classes or IDs to my documents unless I absolutely have to. It's a holdover from the days when I was obsessed with bandwidth (even more than I am now) mixed with a desire to have simple, clean code.
To that end I've developed techniques to access objects and collections of objects anonymously. One of the most powerful tools in that toolbox is getElementsByTagName. I rely on it all the time.
Now, the most straightforward use of getElementsByTagName, and the one people are probably most familiar with is document.getElementsByTagName. Pass a TD or A as an argument and it will return a nodeList of all the TDs or Anchor tags in an entire document. That's great if I want to, for some reason, manipulate every DIV, A or TD on a page. The thing is, I very rarely want to manipulate every single item of a certain type on an entire page. Elements are usually used in multiple ways in a document so, what happens in that situation is there's a huge collection of elements in an array, which have to be looped through and tested for a certain class or other attribute. If I end up doing something like that, I'd rather use a a DOM helper function like getElementsByClass() or something similar. The interesting thing is, you can DOM methods and a little bit of structural markup you can get similar results as getElementsByClass() without having to create any extraneous classes.
That's because, with the way that JavaScript inheritance works, document, isn't the only object that can use the getElementsByTagName method. Any object that represents a document or document fragment (node) can provide scope to getElementsByTagName, so it's easy to limit the the search to a specific object which will represent a specific node in a document. That will then return all child nodes of that Element type of that limited document node. Say, for example, you have a DIV id of "menu". And you want to manipulate all of the LIs that sit inside of that DIV. So you’d use:
document.getElementById("menu").getElementsByTagName("li")
With that you’d get a smaller nodeList of just the child LI nodes of that "menu' DIV. That’s a really neat little collection. from there you can easily manipulate each of those to attach behaviors or to mimic the :hover pseudo class in IE6 with JavaScript or whatever else you need to do.
One other great use of getElementsByTagName is using that method on an XML node. Let’s say I'm using the XMLHttpRequest object and it returns some XML data. JavaScript recognizes that XML data as an object with nodes that you can explore and manipulate. One of the easiest ways to get at that data is to use getElementsByTagName. There are other ways to do it- using childNodes and parentNodes to iterate through the XML to test values and properties and the like is an option, but getElementsByTagName can just grab a collection of XML tags. So say there's an XML document with some arbitrary tags and the script needs to get their value.
In the XHR script the XML response to the request is set to a variable:
xml_document = http.responseXML;
then getElementsByTagName is used
xml_document.getElementsByTagName("yourtag")
which returns a collection of yourtag nodes from the XML document.
One thing I’ll often do, if I know intimately what I’m getting is pass the method a specific index. So if I know I want to get the value of the tag "city" with a name property of "Abington" and I know in advance in the XML document that represents Massachusetts cities and towns, name="Abington" is the first member of that array I can pass the 0 index to the method and return just that node. Like this:
xml_document.getElementsByTagName("city") [0]
Another thing available here is, if I set xml_document.getElementsByTagName("city") to a variable cities, I can loop through that nodeList and then again use getElementsByTagName on each member of the cities nodeList to get individual child nodes of that XML document. It’s really powerful to couple it and loop through to create these collections of collections which can be manipulated in a lot of ways.
Once common place I use getElementsByTagName is to turn a block into a clickable area. As with everything script related, I really prefer to do it anonymously. I don’t want to know in advance how many blocks there will be, what the link will be, etc. I don’t want to know any of that. I really want someone doing some markup to be able to just edit a link in HTML and then the script will come in on the backside and make the magic happen.
So there's a collection of these blocks, and a child node in each of these blocks is an anchor. A real anchor pointing to a real URL. Since, for accessibilities sake, I want to use a real link. I don’t want #s or any of that. So what I would is create a collection of LIs:
menu_lis = document.getElementById("menu").getElementsByTagName("li")
and then loop through that nodeList, using the this keyword and getElementsByTagName to reference the href property of the first A child node of each LI, to build out the JavaScript needed to make the whole block clickable
for (i=0;i< menu_lis s.length;i++) {
setHandler(menu_lis [i],'onclick','document.location=this.getElementsByTagName("a")[0].href');
}
And that's my piece on getElementsByTagName. What's next? Whatever strikes me on my drive in...
[updated to add]
I forgot to point out one use of getElementsByTagName()- using the widlcard "*" argument. Passing the wild card to the method returns a collection of every HTML element in the document. Which is useful when you want/need to flatten the hierarchy to search the elements on a page. I use it in an example script where I search through every node in an XML document testing attributes.
Bob Tulloch Says:
Neat informative article. I will definitely be borrowing these techniques ~ I really liked the combination of ById and ByTag.
PS
Please have a look at my site (www.EuropeanHospitalRegister.com) – any suggestions are gratefully received.
Posted: June 8th, 2007 at 1:11 am
Peter Says:
I'm a beginner playing around with Javascript and I'd like to ask you a question.
I realize the power of document.getElementsByTagName, which is how I found your page, and I'm trying to use it for a simple page I'm trying to create.
I have three menu options at the top of this page, which I am successfully using CSS to achieve a mouse rollover effect for each selection.
When a user clicks on one of these options, I want to store the <a> tag name into a variable using Javascript.
Here's my feeble attempt:
Demographics
Website Traffic
Rates & Availability
And, here's my feeble attempt at creating a Javascript function–GetTg() to store the a tag reference to a variable name using document.getElementsByTagName.
function GetTg() {
var TgVar = document.getElementsByTagName('a');
}
Once I can store the anchor tag to a variable, I want to use it in a switch/case statement to display HTML based on the selection.
Any help is appreciated…
Posted: July 21st, 2007 at 12:22 am
Vladimir Orlovsky Says:
document.getElementsByTagName("city") [0]
Need help!
No body explain how to handle element: "[0]"
in javascript.
What it is? 'index' of some kind.
How do I get it and pass it ?
Thanks.
Vladimir
Posted: August 14th, 2007 at 6:39 pm
rob Says:
this method returns an array, so, yes, [0] is an index. it refers to the first member of the collection (since the count starts at 0). As for how to get it, if you've got a valid tag reference passed as an argument, then you've "got it."
At that point you've got a reference to the object and can do whatever you want with it.
Posted: August 14th, 2007 at 7:35 pm
orlando Says:
i started to use getElementsByTagName by i can't figure it out how to access a property of the tag, for example , i have the following xml response:
Test Contract
i put the id property to identify the contract,
when i handle the response i get the inner text 'Test Contract' with no problem, but how can i access the 'id' property?
thanks,
orlando
Posted: December 14th, 2007 at 12:57 pm
rob Says:
could could try something like
xml_document.getElementsByTagName("city") [0].id;
or
xml_document.getElementsByTagName("city") [0].getAttribute("id");
Posted: December 14th, 2007 at 1:18 pm
Rama Says:
Hi,
Do you have any idea about handling null values which are passed to getElementsByTagName().
For example
var obj = xmlDoc.getElementsByTagName("x")[0];
var objerrorcode = obj.getElementsByTagName("y")[0];
where in xml , x is the parent of y. and y has some childNodes. if the complete tag ( somestuff ) itself is not passed , how can you handle this when y has some childNodes which have to be accessed ?
Posted: April 26th, 2008 at 3:20 am
rob Says:
Hi Rama, I'm not quite following. Do you have some sample XML I could take a look at?
Posted: April 29th, 2008 at 6:59 am
Rafael Says:
Regarding your post #4, I have a small nit-pick which might help someone, as it did make something "click" for me in the past.
getElementsByTagName doesn't return an array. It's an "array-like" collection of HTML elements. If you do this:
alert(document.getElementsByTagName('p'));
in Mozilla, you will be told "[object HTMLCollection]" since that is what it is. In more friendly-speak, it's known as a node list, but it is NOT an array. For example, the Array object's concat method won't work on it because it isn't an array. However, you can loop through it and it has a length property, which is why it is often confused with an array.
Posted: August 25th, 2008 at 6:31 pm
rob Says:
Hi Rafael. Thanks, that's a great point. I do make the point of calling the return a nodeList in the article. In the case of #4 I consciously chose to call it an "array" because I was thinking Vladimir (#3) was new to JS and would probably be confused by the difference between the two. For most beginners the difference doesn't matter.
I actually touch on the differences between nodeLists and arrays several times on the site, most recently in this post on getElementsByClassName
Posted: August 25th, 2008 at 6:42 pm
Craig Says:
Hi,
Regarding #7:
I'm having an issue, i'm storing values from an xml file in a javascript variable. Like:
currentResult.getElementsByTagName("town").item(0).firstChild.nodeValue
I'm doing this using Ajax, my XML results are created on the fly from the database via a super class. Everything is working fine except where a field in my database contains a null value. FF error console says:
currentResult.getElementsByTagName("town").item(0).firstChild is null
I've only just started getting into this Ajax thing, and use Javascript very rarely. I've tried to handle the null value like so:
if(currentResult.getElementsByTagName("town").item(0).firstChild.nodeValue == null)
{
var town = " ";
}
But I still get the javascript error presumably on the conditional statement. It's hard to track the location as I have several PHP, and Javascript files included.
Any ideas on handling the Null value?
Cheers
Craig
Posted: September 11th, 2008 at 4:09 pm
Craig Says:
Arh, got it,
Silly mistake, checking the nodeValue for null, obviously can't happen because it doesn't exist:
if(currentResult.getElementsByTagName("town").item(0).firstChild == null)
Works, Rather than
if(currentResult.getElementsByTagName("town").item(0).firstChild.nodeValue == null)
Thanks anyway, lol
Posted: September 11th, 2008 at 4:34 pm
Kris Says:
Thanks Craig! That saved me a lot of time realizing my own silly mistake :S
Posted: December 17th, 2008 at 12:38 am
Terry Says:
Craig, you just saved my facebook connect site!
In most browsers the fb:profile-pic tag is replaced in parseDom by an img tag with the class of fb_profile_pic_rendered. In Safari on Mac I'm getting the image but the class="". That makes it impossible to reference the image using getElementsByClassName and determine the src of the user thumbnail.
I switched the code to
statusImageSrc=document.getElementById("statusDiv").getElementsByTagName("img")[0].src;and it works every time.
Posted: August 14th, 2009 at 12:21 pm