JQuery Like getElement Method in YUI
One of the many features that I like about jQuery is the ability to pass in CSS selectors and HTML attributes into the ‘jQuery’ for retrieving DOM nodes. YUI has methods for fetching elements by their ‘className’, but not by their HTML attributes, such as ‘type’ or ‘name’. Today, we’ll cover a method I wrote that supports fetching elements by tagName, className, and/or a collection of attributes. The method ‘getElements’ returns all nodes that match any of the tagNames and any of the classNames and every type of attribute (you can have multiple attribute types, such as ‘name’ and ‘type’) provided:
Example 1: getElements
Dom.getElements = function(tagNames, classNames, attributes, root) { var elems = [], nodes = []; // does the root exist, then use it if (root) { root = Dom.get(root); // if no root node, then no children; return empty array if (! root) {return [];} } // otherwise use document else { root = $doc; } // there are tag names provided if (tagNames && tagNames.length) { tagNames.batch(function(tag) { elems = elems.concat(Array.get(root.getElementsByTagName(tag))); }); } // use wildcard '*' for tag name else { elems = Array.get(root.getElementsByTagName('*')).slice(1); if (! elems.length && root.all) {elems = root.all;} // checking for IE < 6 } if (classNames || (attributes && attributes.length)) { var classFn = function(node) {return node;}, attrFn = function(node) {return node;}; // update the classFn to look at a list of classes if (classNames && classNames.length) { classFn = function(node) { return classNames.batch(function(klass) { if (Dom.hasClass(node, klass)) { return node; } }); }; } // update the attrFn to look at a list of attributes if (attributes && attributes.length) { var attributeMap = {}, attributeTypes = []; // iterate on the attributes and create iterables attributes.batch(function(attr) { if (! attributeMap[attr.attributeName]) { attributeMap[attr.attributeName] = []; attributeTypes.push(attr.attributeName); } attributeMap[attr.attributeName].push(attr.attributeValue); }); attrFn = function(node) { var isMatch = true; // iterate on the attribute types to find keys for the attribute value map attributeTypes.batch(function(attributeName) { // iterate on the values and compare with node var n = attributeMap[attributeName].batch(function(attributeValue) { if (attributeValue === node[attributeName]) {return node;} }); // node did not match, stop iterating, since this is not a match if (! n) { isMatch = false; return true; } }); return isMatch ? node : null; }; } // iterate on the nodes found by tags elems.batch(function(el) { if (classFn(el) && attrFn(el)) {nodes.push(el);} }); return nodes; } else { return elems; } };
First, I have shortened “YAHOO.util.Dom” to ‘Dom’ and this function required my Array.js to convert DOM node collections into arrays. The parameters for ‘getElemetns’ are four optional values: an array of tag name strings, an array or class name strings, an array of attribute objects {attributeName, attributeValue}, and the root node to search the DOM from. If the root node is not provided, then ‘getElements’ will start searching from the document, but if an invalid root node is provided, then ‘getElements’ will return an empty array. If tag names are provided, then ‘getElements’ concatenates the results of each into an array (’elems’), but will otherwise default to wildcard (’*'), retrieving all sub-nodes.
When class names or attributes are provided, ‘getElements’ will iterate on the ‘elems’ array and create a new array ‘nodes’ containing the elements that matched the class and attribute values. However, if neither is provided, we simply return the ‘elems’ array. To determine if the classes and/or attributes are present on a node, we create functions that take a node as a parameter and return that node when the value matches. The class name function will test to see if the node contains any of the classes in the array. The attribute function first creates a map of values for each type of attribute that is provided, then iterates through them, only returning true when the node matches at least 1 attribute of each type.
Here is an example that starts searching for ‘input’ and ‘a’ tags, with either class ‘button’ or ‘link’, and has the name ’submit’:
Example 2: Using ‘getElements’
Dom.getElements(['input', 'a'], ['button', 'link'], [{attributeName: 'name', attributeValue: 'submit'}], 'myRootNode');

Matt,
I’m really confused here. Why did you reimplement the Selector Utility?
Comment by Paul Irish — October 29, 2008 @ 8:24 am
Paul,
The selector is still in beta and not part of yahoo-dom-event.js, and this is a little faster, as it doesn’t have to parse the string. In the end the selector will be more powerful, because you can more finely tune the specificity of each element type you want to find. However, this comes at a performance price.
I also wrote this method for my own projects, before the selector existed.
Comment by Matt Snider — October 29, 2008 @ 9:39 am