views:

120

answers:

2

Without using any open source framework (jQuery, etc.) :), in JavaScript, what's the most efficient way to search for attributes in any controls. (Any old/new browsers)

This is the pattern I'm kind of following. Is there any better way or any better getElementByAttribute() method? Thanks!

e.g

<input type="button" id="b1" value="Continue" a1="something" />
<input type="text" id="t1"  a1="something1" />

<script>
var attrToFind = "something;something1";

var elems = document.all ? document.all : document.getElementByTagName("*");
//assume elems work always
for(var i = 0 ; i < elems.length; i++)
{
  var att = elems[i].getAttribute("a1");
  if (typeof att == "string")
  {
    if (att.indexOf(attrToFind) > -1)
    ... //search which attr you find, create array, save value, etc.
  }
}
</script>
+1  A: 

There is. Given that browser supports other means to collect elements, such as document.querySelectorAll (css expression) or document.evaluate (xpath expression), these "specialized" methods are usually more efficient.

document.querySelectorAll('*[foo="bar"]');
document.evaluate("//*[@foo='bar']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
kangax
@kangax: Interesting...didn't know about querySelectorAll at all. I believe it won't work on new and old browsers so I can't use it really.@Shog9: yup, being slower with my way is my fear as well. That's why I posted the question here to ask the JS gurus.
Rac123
Yeah, you end up having to write a wrapper function that uses one of these methods if available, else falls back to walking the whole document. This is what many frameworks do (although some of them don't get the string escaping right...)
bobince
+1  A: 

Accessing an HTMLCollection (returned by getElement[s]By* functions) is slow in comparison to accessing arrays because an HTMLCollection must match the document at all times (it is live).

For this reason, it's best to create an array from the HTMLCollection and iterate over that.

This is a bit more optimized for speed:

var attrToFind = "something;something1",
    elems = document.all ? document.all : document.getElementByTagName('*'),
    i, attr;

// Works in Firefox; not sure about other browsers and engines.
elems = Array.prototype.slice.call(elems);

i = elems.length;

while(i --> 0) {
    attr = elems[i].getAttribute('a1');

    // Are you sure you want indexOf?
    // att === attrToFind may be faster, as it requires one less comparison.
    if(typeof att !== 'string' || att.indexOf(attrToFind) < 0) {
        continue;
    }

    // Do stuff.
}
strager
@stranger: the code snippet looks optimistic. Let me try. Thx!
Rac123
Yeah, IE6 didn't like Array.prototype.slice.call(elems) and unfortunately (for all of us) that I've to support it.
Rac123
@Rac123, You can probably just iterate over and copy it to a new array for IE6. Add a try block, perhaps, around the current collection-to-array line, than in the catch do the naive solution.
strager