8
\$\begingroup\$

I needed to write a function today in JavaScript that would return all elements based on a given attribute.

e.g retrieve all elements that have an id attribute in them.

The function I wrote for this is as follows:

function getElements(attrib) {
    // get all dom elements
    var elements = document.getElementsByTagName("*");
    // initialize array to put matching elements into
    var foundelements = [];

    // loop through all elements in document
    for (var i = 0; i < elements.length; i++) {
        // check to see if element has any attributes
        if (elements[i].attributes.length > 0) {
            // loop through element's attributes  and add it to array if it matches attribute from argument
            for (var x = 0; x < elements[i].attributes.length; x++) {
                if (elements[i].attributes[x].name === attrib) {
                    foundelements.push(elements[i]);
                }
            }
        }
    }
    return foundelements;
}

Looking at this, I am sure it could be written a great deal better. Any feedback would be much appreciated!

\$\endgroup\$
9
\$\begingroup\$

querySelectorAll

First off, if you're only dealing with relatively modern browsers (basically anything above IE7), you can use querySelectorAll, which is the fastest and easiest method to go about this:

document.querySelectorAll('[' + attrib + ']');

Here's the fiddle: http://jsfiddle.net/rc6Pq/


Sizzle

If you're stuck having to support IE7 and below, then you might as well just include the Sizzle selector engine, since you're bound to be using some additional selectors in the future. Once you include the Sizzle script in your page, you could then just use it in a similar fashion to the native querySelectorAll:

Sizzle('[' + attrib + ']');

Here's the fiddle: http://jsfiddle.net/rc6Pq/1/


jQuery

If you're already using jQuery on the page, you don't have to use Sizzle separately, since jQuery has Sizzle incorporated within it. If that's the case, just use this:

$('[' + attrib + ']').get();

Here's the fiddle: http://jsfiddle.net/rc6Pq/2/

\$\endgroup\$
  • \$\begingroup\$ This helped a great deal Joseph, thank you for your input! \$\endgroup\$ – John H Jul 27 '12 at 16:36
3
\$\begingroup\$

I'm not too familiar with JS, so just three generic notes:

  1. It seems to me that the elements[i].attributes.length > 0 check is unnecessary because the statements inside the following for loop won't if elements[i].attributes.length is zero.

  2. Consider creating local variables for elements[i] and elements[i].attributes. It would remove some duplication.

    for (var i = 0; i < elements.length; i++) {
        var currentElement = elements[i];
        var currentAttributes = currentElement.attributes;
        for (var x = 0; x < currentAttributes.length; x++) {
            if (currentAttributes[x].name === attrib) {
                foundelements.push(currentElement);
            }
        }
    }
    
  3. It might be easier with jQuery: find element by attribute.

\$\endgroup\$
  • \$\begingroup\$ I didn't realize that the check in your first note was unnecessary, I thought the interpreter might throw an error if it tried to loop something that wasn't an array. Your second note helped make my code more readable. Thank palacint! \$\endgroup\$ – John H Jul 27 '12 at 16:40
  • \$\begingroup\$ @JohnH element.attributes is never an array; it's an array-like object. But even when there are 0 attributes, it is set to an object with a length of 0. So, the first comparison of the loop would return false without error. \$\endgroup\$ – delete me Jul 30 '12 at 18:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.