Techy Treasures #4: What’s inside a dollar function?

    James Edwards
    Share

    Today’s Techy Treasure is another basic staple for me, something simple, but which I use in virtually every script I write. It’s a method for retrieving element references — either single elements, or collections of elements referenced by tag name, and optionally filtered by attribute match.

    Most JavaScript libraries have a function like this, often calling it $ (dollar). And while all of them work slightly differently, they all do basically the same thing. So if you’re new to JavaScript, and been wondering what’s inside those ubiquitous dollar functions, here’s a bit of anatomy for you!

    As with all the methods I’ve written about in this column, I’m demonstrating it here as a global function, to make the examples more straightforward; but in practise you’d do better to define it as a method of a custom object:

    function get(find, context, conditions)
    {
    	if(find.indexOf('#') != -1)
    	{
    		return document.getElementById(find.split('#')[1]);
    	}
    
    	else 
    	{
    		if(typeof context == 'undefined') 
    		{ 
    			context = document; 
    		}
    		
    		var nodes = [], tmp = context.getElementsByTagName(find);
    		for(var i=0; i<tmp.length; i++)
    		{
    			nodes.push(tmp[i]);
    		}
    		
    		if(typeof conditions == 'undefined')
    		{
    			return nodes;
    		}
    		
    		var filtered = [];
    		for(i=0; i<nodes.length; i++)
    		{
    			var add = true;
    			for(var c in conditions)
    			{
    				if(!conditions.hasOwnProperty(c)) { continue; }
    				
    				var attr = c == 'class' 
    					? nodes[i].className : nodes[i].getAttribute(c);
    					
    				if(attr == null 
    					|| attr == '' 
    					|| new RegExp('(' + conditions

    + ')', '').test(attr) == false)
    {
    add = false;
    }
    }
    if(add == true)
    {
    filtered.push(nodes[i]);
    }
    }
    return filtered;
    }
    }

    The get() method does three things. Firstly, it can retrieve a single element, a shorthand for getElementById:

    var content = get('#content');

    Secondly, it can retrieve a collection of elements, a shorthand for getElementsByTagName:

    var paragraphs = get('p');

    But thirdly, and most interestingly I think, it can filter a collection of elements according to attribute matches. What this feature amounts to is a getElementsByAttributeMatch() method, where multiple attributes can be matched in a single expression:

    var codeblocks = get('code', document, { 
    	'class':'javascript' 
    	});

    This third example is retrieving a collection of <code> elements which have the class name “javascript”; or to be more precise, elements where the value of the class attribute contains the string “javascript”.

    In fact the value parameter of each key/value pair is evaluated as a regular expression, so you could do things like this:

    var codeblocks = get('code', document, { 
    	'class':'j(ava)?script|php' 
    	});

    You’ll notice in those examples that there’s a second argument before the condition object, which defines the context of the search. You can pass in a different document reference to retrieve a collection in that context (such as a page inside an iframe), or you can pass in an element reference to retrieve a collection of child elements within a specific element (such all list-items within a list).

    Finally, what this method returns also depends on what you ask it for. For a single element it will return either that element or null; for a collection of elements (whether filtered by attribute conditions or not) it will return an array of elements (a true JavaScript array, not a DOM collection), and if no matching elements were found this array will be empty.