Manipulating the DOM, Google Closure vs. jQuery
Comparing closure to jQuery is like comparing an apple to a fruit basket.
Google Closure, a JavaScript library and compiler, features cross-browser event management, drag and drop support, shared server and client side templating, and a massively efficient code compressor. Closure was used and refined at Google for years before it was released at the end of 2009 as open-source.
jQuery is a tool for making cross-browser dom manipulation, event management, and Ajax interactions easy and fast. It was built with the philosophy that the API should be concise and intuitive.
We can use jQuery and Closure together; however, using Closure’s own libraries for DOM manipulation, we should get smaller, faster apps.
To understand Closure’s DOM library, the rest of this article looks at:
- DOM Search
- Element Creation
- Element Manipulation
- Adding & Removing Classes
- Styling Elements
DOM Search
The easiest way to detect the differences between the way these two libraries find elements is to look at a nested search.
1 2 3 4 5 6 7 8 |
<code> // jQuery
var articles = $('#articles .article');
// do some stuff with the articles
var links = articles.find('a.more'); // find deeper nested elements
// a more succinct search, if the articles array is not needed
$('#articles .article a.more');
</code> |
jQuery’s API uses arbitrarily complex css selectors to find elements. When the elements are returned, they are wrapped with jQuery’s DOM manipulation functionality.
Closure on the other hand prefers using a number of methods for making very particular kinds of selections. The returned value is a DOM node, which can then be passed to other functions. A similar element query in Closure can be seen below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<code>
// Closure
goog.require('goog.dom'); // the library that provides DOM selection functionality
var articles = goog.dom.getElementsByClass(
'article', goog.dom.getElement('articles')
);
goog.require('goog.array');
var links = goog.array.map(articles, function(article) {
return goog.dom.getElementsByTagNameAndClass(
'a', 'more', article
)[0];
});
</code> |
goog.dom.query to the Search Rescue
Clearly some Closure developers felt the pain of DOM navigation. A library, ‘goog.dom.query’, was built by third-party engineers, to emulated the DOM searching capabilities of Dojo, http://dojotoolkit.org/. The above closure code can be reduced to:
1 2 3 4 5 |
<code> // Closure with the third-party library 'query'
goog.require('goog.dom.query');
goog.dom.query('#articles .article');
goog.dom.query('#articles .article a.more');
</code> |
Documentation for this library is more scant than in other places in Closure. There does not appear to be a way to pass in a DOM node to act as the root element for the search.
Element Creation
The abilities of jQuery and Closure are more closely aligned when it comes to the creation of DOM elements.
jQuery leaves the developer to build the base html tag for an element out of strings. After, creating the element, it is easy to add attributes to the tags. jQuery also makes it easy to append nodes to elements.
1 2 3 4 5 |
<code> // jQuery
var articles = $("<div />").attr('id', 'articles');
articles.append($("<div class='article'></div>").text('article content here!'));
$(body).appendChild(document.body, articles);
</code> |
Closure lets its developers create elements on a lower level, by just passing in the tag name. The second argument is a hash of properties. Alternately, the second argument can be a string, which will be understood as the class name. Finally, the third argument defines the inner content of the element. The inner content can be text or it can be another created element.
1 2 3 4 5 6 7 8 |
<code> // Closure
articles = goog.dom.createDom(
'div',
{id: 'articles'},
goog.dom.createDom('div', 'article', 'article content here!')
);
goog.dom.appendChild(document.body, articles);
</code> |
While simple string concatenation is intuitive in jQuery, the Closure approach will yield a more robust implementation of an HTML tag. Its nested creation syntax, though cumberson to read at first, will likely be more powerful to use.
Element Manipulation
The last area that I wanted to address in the comparison between jQuery and Closure is the manipulation of individual DOM element attributes. The two main attributes of concern are classes and styles, which require adding and subtracting values from a string, not simply replacing the value.
Adding and Removing Classes
jQuery and Closure have fairly similar interfaces for changing class names on an element:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<code> // jQuery
var element = $('#articles');
element.addClass('mobile'); // adds it to any existing classes, creating the property as needed
element.toggleClass('hidden'); // removes the class if it exists, adds it if it doesn't
element.removeClass('gerbil-bate');
// Closure
goog.require('goog.dom.classes');
var element = goog.dom.getElement('articles');
goog.dom.classes.add(element, 'mobile');
goog.dom.classes.remove(element, 'hidden');
goog.dom.classes.toggle(element, 'gerbil-bate');
</code> |
This is an area where I think the Closure syntax is very intuitive. The namespacing with small function names is very easy to read and understand. Within this library there are also intuitive methods like ‘has’, which returns a boolean value indicating whether the class name is in the string.
Styling Elements
Closure organizes its ‘goog.style’ namespace into a series of getters and setters for individual style attributes. jQuery uses a single methods, with two signatures. One signature is for getting, the other is for setting.
1 2 3 4 5 6 7 8 9 10 11 12 |
<code> // jQuery
var element = $('#articles');
element.css({'background-color': '#666'}); // setting a css attribute in the style property
element.css({left: '320px'}); // this is non-destructive, the background-color is not removed!
element.css('left'); // returns '320px'
// Closure
var element = goog.dom.getElement('articles');
goog.style.setStyle(element, {'background-color': '#666'});
goog.style.setStyle(element, {left: '320px'}); // this is also non-destructive
goog.style.getStyle(element, 'left'); // like jQuery, it returns the string value
</code> |
Closure provides a number of very specific setters and getters in addition to these two basic ones. The more specific setters sometimes take exotic arguments designed to ease the pain of CSS calculations. For example, the ‘setContentBoxSize’ method takes as its second argument a ‘goog.math.Size’ object in order to set the dimensions of the element.
Conclusion
Both Closure and jQuery get the job of DOM navigation done using different philosophies and styles.
Part of Closure’s steeper learning curve is not only its sparse documentation, but that every namespace uses different conventions for API design. The diversity of conventions means that we need to do more memorization of API method names, argument signatures and return types. With jQuery there is single pattern that is applied consistently.
The consistency of jQuery’s API is a big plus for me. I find that when I am not thinking about the minutiae of my tools, I am better able to keep my focus on solving the problems at hand. That translates to faster development and faster time to market.
2 Comments
Nice one would love to see more comparsions :)
Closure may look clunky but you didn’t mention one killer feature: it has a huge set of controls. jQuery UI has only a very small set of controls - nothing close to what’s needed for a commercial application. If you need a text editor, editable table, combo box, etc. etc. you’ll be out of luck with jQuery, trying to get lousy 3rd-party plugins to work, or spending thousands of dollars on professional controls library.
With closure the controls are built in. Eat that, jQuery.