I'm currently on parental leave till September 1st. Until then, I will not be available to read comments, e-mails, tweets and Facebook messages.

If you are interested in my writings, please subscribe to my RSS feed and follow me on Twitter.

Monday code giveaway: getElementsByAttribute

Updated September 27th 2006

Apparently Opera’s claim to support document.all in conjunction with not mimicking it exactly like IE led to some problems in Opera 9. Thanks to Ash Searle who tipped me about this and also explained what the problem was. The code below and the JavaScript file to download are updated.

Since we all have to face a new hard tough week now, I thought I’d brighten your day by giving you some code that might be useful.

Ever run into a situation where you want to get an array of all elements with a specific attribute? Or even want elements with a certain value for that chosen attribute, as well? That’s not a problem anymore; let me present getElementsByAttribute.


/*
	Copyright Robert Nyman, http://www.robertnyman.com
	Free to use if this text is included
*/
function getElementsByAttribute(oElm, strTagName, strAttributeName, strAttributeValue){
	var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
	var arrReturnElements = new Array();
	var oAttributeValue = (typeof strAttributeValue != "undefined")? new RegExp("(^|\\s)" + strAttributeValue + "(\\s|$)") : null;
	var oCurrent;
	var oAttribute;
	for(var i=0; i<arrElements.length; i++){
		oCurrent = arrElements[i];
		oAttribute = oCurrent.getAttribute && oCurrent.getAttribute(strAttributeName);
		if(typeof oAttribute == "string" && oAttribute.length > 0){
			if(typeof strAttributeValue == "undefined" || (oAttributeValue && oAttributeValue.test(oAttribute))){
				arrReturnElements.push(oCurrent);
			}
		}
	}
	return arrReturnElements;
}

The parameters are:

oElm
Mandatory. This is element in whose children you will look for the attribute.
strTagName
Mandatory. This is the name of the HTML elements you want to look in. Use wildcard (*) if you want to look in all elements.
strAttributeName
Mandatory. The name of the attribute you’re looking for.
strAttributeValue
Optional. If you want the attribute you’re looking for to have a certain value as well.

And these are a couple of examples how it can be called:


getElementsByAttribute(document.body, "*", "id");
getElementsByAttribute(document.getElementById("the-form"), "input", "type", "text");

Web browser compatibility

The code has been tested and verified to work in:

  • All Firefox versions, all the way back to Firebird (remember that one? :-) )
  • IE 5.0+, PC
  • IE 5.2, Mac
  • Safari 1.3
  • Opera 7.03

To use it, just copy and paste above code or download the getElementsByAttribute.js file.

43 Comments/Reactions

  • #1 Jeroen Mulder
    January 23rd, 2006 at 15:21

    Ok, as someone knowing the basics of DOM scripting, I think this looks really sexy and I can think of many uses for it.

    Thanks for sharing. It’s nicely tucked away in my bookmarks now. :-)

  • #2 Emil Stenström
    January 23rd, 2006 at 15:21

    Nice! This will really come in handy. I have used Jonathan Snook’s getElementsByClassName before but I think it’s time for a change. Thanks for sharing.

  • #3 Marco
    January 23rd, 2006 at 16:10

    Very nice! This will surely come in handy at times just like the getElementsByClassName thing.

  • #4 Alexander
    January 23rd, 2006 at 17:08

    Thank you, Robert!

  • #5 Jules
    January 24th, 2006 at 2:07

    You know I need to know more JavaScript when I read that you were giving away a function called getElementsByAttitude.

    So, which elements have attitude?

  • #6 Robert Nyman - author
    January 24th, 2006 at 9:34

    Jeroen,

    Thanks!

    Emil,

    Thank you! Regarding getElementsByClassName, I wrote an improved version, inspired by Snook’s initial one.

    Marco, Alexander,

    Thanks!

    Jules,

    Ha ha! :-)
    Well, it just has to be the strong element, right? :-)

  • #7 Chris
    January 24th, 2006 at 11:16

    Great! Just yesterday I needed this function. Thanks Robert.

  • #8 Robert Nyman - author
    January 24th, 2006 at 11:32

    Chris,

    Great, I’m glad I could help!

  • #9 Anne van Kesteren
    January 26th, 2006 at 12:40

    Mozilla has this native for Document objects implementing the XULDocument interface.

  • #10 Robert Nyman - author
    January 26th, 2006 at 13:06

    Anne,

    Ah, interesting to hear!

  • #11 Rowan Lewis
    January 26th, 2006 at 13:22

    Nice spotting Anne!

    Robert, thanks for sharing, functions like this should always have been part of the spec…

  • #12 Robert Nyman - author
    January 26th, 2006 at 13:42

    Rowan,

    Yes, this one and getElementsByClassName are good examples of things that should be native.

  • #13 Hakan Bilgin
    January 29th, 2006 at 4:12

    A little to much coding for my taste. What do you think about this one?

    // Javascript

    function getChildren(el, a, v) {
        var ar = new Array();
        var ac = document.getElementById(el).getElementsByTagName(‘*’);
        for (c=0; c<ac.length; c++) if (v? (ac[c][a] == v) : (ac[c][a])) ar.push(ac[c]);
        return ar;
    }

    // Usage
    getChildren(elementId, attribute, value);

    // Sample
    var col1 = getChildren(‘my_element’, ‘className’, ‘menuitem’);
    var col2 = getChildren(‘my_element’, ‘nodeName’, ‘IMG’);
    var col3 = getChildren(‘my_element’, ‘onclick’);

    The third parameter (value) is optional…if undefined the function will return any element with specified attributename, regardless value.

    /hbi

  • #14 Robert Nyman - author
    January 29th, 2006 at 9:36

    Hakan,

    Very short and concise, which I like! However, there are a few problems with it.

    getElementsByTagName(’*') only works on the document element in IE 5, and not on any other element; hence the usage of document.all.

    Just checking for v? will return false in that if clause if you would indeed want to look for an attribute with the value 0.

    Referring to directly to an attribute’s name through an array ((ac[c][a] == v)) didn’t seem to work in Safari, and it threw an unexplainable error in IE on some elements. Another problem with this value comparison is that it’s case-sensitive, while some web browser are notorious for changing the case when the elements and attributes are created in their DOM.

    Finally, the reason for checking the length of the attribute value is because IE automatically creates a lot of attributes for every element in the DOM at runtime, so I want to make sure that is an attribute created intentionally by the programmer.

  • #15 EuGene C. White
    February 3rd, 2006 at 23:30

    I am trying to use your code and keep getting errors that an object is required. Front Page even tells me that the HTML is no good. At this point, I suppose that is possible. Here is the button code I am trying to use to get it to run. What I am trying to do is find a div id tag that equals a certain value and then pass it to another function that I kinow works. I am trying to provide buttons on a page to copy specific code. The code I use works when I only have one code copying area per page. If I have two, then it will not work. So I figured that fi I could use code to find a specific one and then copy only that one, it might work. In any event, here is the button code that I use:

    Eval –>

    Thanks,

    Gene

  • #16 Robert Nyman - author
    February 4th, 2006 at 21:25

    EuGene,

    I think you didn’t escape the HTML code properly when you posted your comment (&lt; for < etc) . To get a reference to an element with a certain id, just use document.getElementById("element-id") (remember that ids are supposed to be unique, meaning that only one instance of a certain id is correct).

    If that doesn't solve your problems, I think there might be two otherreasons why it doesn't work.

    1) The first parameter has to be an object reference to the container where you want to look for your objects. Make sure it's valid.

    2) You will not get back an object but an array reference from the function. I.e., if you think you will only get back one object, you need to reference it like this:

    var oObject = getElementsByAttribute(document.body, "*", "id")[0];

    Good luck!

  • #17 Marko Dugonjić
    March 1st, 2006 at 8:35

    Hi, it’s a nice snippet.

    However, you might consider alternative for the push() which is not supported by IE 5.0/Win.

  • #18 Robert Nyman - author
    March 1st, 2006 at 8:44

    Marko,

    That’s the reason why there’s also an implementation for the push method for the Array object in the downloadable JavaScript file.

    However, maybe I should’ve pointed this out in the post as well…

  • #19 Sten Hougaard
    March 17th, 2006 at 15:40

    Great implementation of a general method! :-)

    And now for my wish: Could it be possibel to add a NAMESPACE parametre? You know if I add my own namespace – say “CSL” and have an attribute set on an INPUT tag: <INPUT type=”TEXT” CSL:KeepForHours=”1″>

    Your method wil not be able to find elements based on attributename “CSL:KeepForHours” will it?

    Why would I use namespace?
    - I am working on an easy way to add cookie support for any tag through simpel HTML mark-up and a Javascript Library.

    The Attribute I am considering to put in it’s own namespace. An example way to ensure that a value will live across sessions would be like the input tag named above. In that example the value of the input tag would live for 1 hour by using cookies :-)

    Cheers!

    /Sten
    Denmark

  • #20 Robert Nyman - author
    March 20th, 2006 at 13:19

    Sten,

    Thank you!

    What you can do is just tweak the function to use the getAttributeNS method.

  • #21 Robert’s talk » AJAX, JavaScript and accessibility
    March 23rd, 2006 at 14:53

    [...]getElementsByAttribute[...]

  • #22 aNieto2K | Lo que quiero, cuando quiero y como quiero » getElementBy…
    May 4th, 2006 at 11:44

    [...] bsp;  Firefox 1.0+, Mozilla ?, Opera ? * getElementsByAttribute     * getElementsByAttribute (parent, tag name, attribute name, attribute [...]

  • #23 bob
    May 18th, 2006 at 13:07

    third time I’ve come back for this after losing it – about time I said thanks.

    thanks.

  • #24 jim
    June 20th, 2006 at 11:26

    Hi,

    I haven’t done extensive testing on this, but I seem to have stumbled across a problem with custom attributes.

    I have following element:

    <input type="button" foo="bar" value="initValue"/>

    If I call your function as follows:

    var buttons = getElementsByAttribute(document.body, 'input', 'foo', 'bar');

    I get null result in Firefox 1.5.0.4 (it’s ok on IE6).
    By changing your line:

    oAttribute = oCurrent.getAttribute(strAttributeName);

    to instead use eval() to do direct property access:

    oAttribute = eval('oCurrent.'+strAttributeName);

    it seems to work ok on both Firefox and IE6. I’m assuming there is no intentional restriction in getAttribute function with regards to custom attributes, and that this is just a bug in Firefox Element::getAttribute.
    Thanks for your function!

  • #25 Robert Nyman - author
    June 20th, 2006 at 14:34

    Jim,

    I didn’t know that. My guess is that it is probably intentional by Firefox since they want to be as valid and correct as possible, and custom attributes shouldn’t be in the HTML code (this is a big discussion for another day… :-) ) and aren’t allowed if you want to have a web page with valid code (unless you use a custom DTD and so on).

    Anyway, with that said, if you have that specific need for custom attributes I’m happy to hear that your workaround seems to work out fine for you. However, I will let this function hold on to the W3C recommended way of accessing attributes in the DOM.

  • #26 Hakan Bilgin
    September 14th, 2006 at 0:23

    Hi Robert,
    I am currently experimenting with “custom” namespaces and have discovered that the interface in Firefox is a little unsatisfactory. For instance in IE, with the properties scopeName and nodeName, I can find out contextual information about a certain element.

    In Firefox, scopeName does not exist at all (but I have extended as seen below) and nodeName returns both the namespace and the nodeName, united by a colon…in upperCase.

    Node.prototype.__defineGetter__(‘scopeName’, function() {
    var nn = this.nodeName.toString();
    return (nn.indexOf(‘:’) > -1)? nn.split(‘:’)[0].toLowerCase() : ‘HTML’ ;
    });

    I find the Firefox interface poor and limiting. But than again, I might be missing out on something…so I hope you shed some light to the subject. Do you know any way to extract the properties of an element in a suitable way in Firefox?

    BR,
    /hbi

  • #27 Robert Nyman - author
    September 14th, 2006 at 12:26

    Hakan,

    Unfortunately, I don’t have an answer for you. I never get time nor assigned to play around with such fun stuff! :-)

  • #28 Hakan Bilgin
    September 14th, 2006 at 16:57

    Ok…thanx anyway.

    /hbi

  • #29 Simon
    October 21st, 2006 at 20:59

    Works great in firefox and opera but not at all in IE6 for my implemention.
    But as it’s the class I wanted I found your getElementsByClassName which worked fine in all 3 browsers.

  • #30 Robert Nyman - author
    October 22nd, 2006 at 21:29

    Simon,

    Weird… I use it all the time and haven’t ahd any problems with IE 6. For example, with my GLT library it’s vital.

  • #31 Matthew Krivanek
    November 5th, 2006 at 18:43

    What I’m trying to do is find all instances of inline styles and remove them.

    However, it seems that the attribute ‘style’ does not get returned in IE. I’ve tested in other browsers and the ‘style’ attribute is found, but IE, the array is returned empty.

    Any thoughts on how to make this work?

  • #32 Matthew Krivanek
    November 5th, 2006 at 19:54

    It’s seems I may have found a solution, however, not so graceful.

    Due to the way IE works, when trying to get the ‘style’ attribute, IE’s getAttribute function returns an object.

    The work around I found was to set the oAttribute variable using the .cssText property for IE. I believe that the ‘style’ attribute is the only attribute stored as an object in IE. I could be wrong though…

    My modification to your function:


    /*
    Copyright Robert Nyman, http://www.robertnyman.com
    Free to use if this text is included
    */
    function getElementsByAttribute(oElm, strTagName, strAttributeName, strAttributeValue){
    var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
    var arrReturnElements = new Array();
    var oAttributeValue = (typeof strAttributeValue != "undefined")? new RegExp("(^|\\s)" + strAttributeValue + "(\\s|$)") : null;
    var oCurrent;
    var oAttribute;
    for(var i=0; iif(typeof oAttribute == "object"){
    oAttribute = oAttribute.cssText;
    }
    if(typeof oAttribute == "string" && oAttribute.length > 0){
    if(typeof strAttributeValue == "undefined" || (oAttributeValue && oAttributeValue.test(oAttribute))){
    arrReturnElements.push(oCurrent);
    }
    }
    }
    return arrReturnElements;
    }

  • #33 Matthew Krivanek
    November 5th, 2006 at 20:10

    Ok, so, my code broke Firefox. This is dirty, but works.

    if (navigator.appName == 'Microsoft Internet Explorer')
    {
    oAttribute = oAttribute.cssText;
    }

  • #34 Robert Nyman - author
    November 6th, 2006 at 9:56

    Matthew,

    Interesting. However, the way I see it, style isn’t really an attribute in that sense. You never set a style through setAttribute, but instead by using the .style notation.

    If your code works in your case, I’m happy for you, but I don’t find it necessary to incorporate in the standard version of the script.

    A little suggestion: Instead of checking for web browser name, you can use if(document.all) and then a check for if(typeof oAttribute.cssText != "undefined).

  • #35 EJ – The only JavaScript library you’ll ever need – Robert’s talk
    November 7th, 2006 at 12:24

    [...] d, if you want to, a certain value in that attribute as well. More thoroughly described in Monday code giveaway: getElementsByAttribute. preventDefau [...]

  • #36 Matthew Krivanek
    November 12th, 2006 at 1:50

    Thanks for the tip and thanks again for the script!

    -mk

  • #37 Robert Nyman - author
    November 13th, 2006 at 9:00

    Matthew,

    No problem at all! I hope everything works out for you.

  • #38 Gary
    December 1st, 2006 at 23:00

    Okay, so I’m wondering if someone could kindly help me with this a bit. Long story why, but in essence I want to find the ID of a single div element among many which have been dynamically generated in javascript (each element is assigned an ID along the lines of cell_1_2, cell_1_3, etc). That element has a unique style (a background color) and is the only element belonging to a specific class (called “highlighted”).

    I’m not sure if this is the right function, or if getElementByClass is better, but in either case I’m having a hard time returning the ID of that single element.

    Any thoughts? Much appreciated …

  • #39 Kok Chuan
    February 3rd, 2007 at 19:19

    Hi, this code works great. However i’ve found something that causes it not to work properly.

    when i create a “input” form control without specifying the type, it defaults to type=”text”. your current script is not able to work with this “lazy” coding :D

  • #40 separati.st » Daily Interesting Shizzle for February 25th
    February 25th, 2009 at 14:28

    [...] Monday code giveaway: getElementsByAttribute – Robert’s talk – Web development and Internet tr… [...]

  • #41 Obteniendo elementos mediante selectores de atributos en Javascript – JSEROS Diseño y Desarrollo web | General
    April 7th, 2009 at 12:44

    [...] fuera de un framework como jQuery o Mootools. Actualmente existen unas cuantas escritas como la de Robert Nyman y la incluida en el diccionario XUL de desarrollo de extensiones para [...]

  • #42 getElementsBy* « Dogfeeds——IT Telescope
    June 13th, 2009 at 7:57

    [...] getElementsByAttribute [...]

  • #43 paul
    April 29th, 2010 at 14:25

    Robet u did a grat job, really a very helpful example indeed

Write a comment

Twitter reactions

Share your thoughts:

HTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> . If you want to display code examples, please remember to write &lt; for < and &gt; for >.

Comment preview