At the Forge - jQuery
JavaScript has become, somewhat surprisingly, one of the hottest programming languages around. The question is not whether Web developers need to know JavaScript, but rather what library they should use when working with it. That's because the core JavaScript language is a bit rough around the edges, with incompatibilities across different browsers and platforms. This is compounded somewhat by other cross-platform browser differences, such as various ways that event handling is implemented, which can make it hard for developers to deal with such problems.
Most of my Web development work in the past few years has been in the Ruby language in general and the Ruby on Rails framework in particular. Rails comes with a high-quality JavaScript library called Prototype, and I have written several columns describing how to use Prototype, as well as the Scriptaculous effects library that builds upon its language improvements.
Prototype isn't going away. But, over the past few months, I've noticed a growing interest—from within the Rails community and from other developer communities as well—in jQuery, another high-quality, open-source JavaScript toolkit. Most significant, jQuery was chosen by Microsoft as the official JavaScript library for its developers. jQuery also has a large number of ready-made plugins, including many that provide user-interface functionality. And, as I've started to explore jQuery, I'm beginning to think that its fans have a point, and I've even started to consider switching some of my work away from Prototype to jQuery.
What makes jQuery so special and different? What does it offer? And, how can you integrate it into your applications? This month, I try to answer all of these questions, as we explore some of the basic features of jQuery. Next month, we'll look at some of the UI widgets that jQuery provides to spruce up our sites and make them more functional.
jQuery was first released in 2006, based on preliminary work that John Resig had done since August 2005, as a simple JavaScript library that would make it more convenient to develop Web applications. Over time, it has grown to include many contributors. Resig himself has written two books on JavaScript and now works for the Mozilla corporation as a JavaScript evangelist.
If you have used Prototype previously, you won't be surprised to know that $() is not only a legitimate function name in JavaScript, but it's also used extensively within jQuery. However, $() works differently in jQuery than in Prototype. In Prototype, you can say:
$('foo') // Prototype
to get the elements with id attributes of foo and bar. The number of parameters to Prototype's $() determines whether it returns a single value or an array, as well as how many elements that returned array contains.
Prototype also lets you retrieve items using CSS selectors (and a variety of pseudo-selectors), using the $$() function. For example:
$$('tr.even') // Prototype
returns an array (and always an array, even if it matches only a single object) of all of the tr tags with a class of even.
Well, jQuery works similarly, except that it has only a single function, $(). That function is smart enough to recognize what you want, based on a single CSS-style selector that you give it. (And yes, you may specify only a single selector.) However, id attributes need to begin with a # character, as is the case in CSS. Thus, you can say:
$('#foo') // jQuery
to get all the tags (and there should be only one such tag) that have an id attribute of foo, and:
$('tr.even') // jQuery
to get all the tr tags with a class of even. Each call to $() might return zero, one or a number of objects matching that selector. That is, if you were to say:
$('#blahblah') // jQuery
and there isn't any such item, jQuery happily will return the set of elements matching that query—an empty set.
This might seem a bit weird at first. After all, don't you need to know in advance how many results you'll get, or even if there will be results at all? Otherwise, how can you know whether to call a function on the one returned element or to iterate over a set of elements and call the function on each of them?
Things make much more sense once you understand that many of jQuery's functions operate using what's known as implicit iteration. That is, you can say:
$('p').show();
and jQuery will grab all the paragraphs in a document and show them. If there aren't any paragraphs, nothing happens. If only one paragraph matches, it is shown (if it wasn't showing already). The idea that you don't have to use an each() loop to go through each element is a powerful one, and it repeats itself often in jQuery code.
Equally powerful is the fact that most jQuery methods return the same set they were passed. For example, if we want to show all paragraphs and then make their background color red, we could say:
$('p').show().css({'background-color': '#f00'});
Chaining methods together in this way is quite typical in jQuery, and it helps make code more readable and concise.
When I first saw the way jQuery uses $(), I realized this meant I probably wouldn't be able to use both jQuery and Prototype in the same program, because there would be a namespace collision between $() in each of the two systems. However, the authors of jQuery thought about this very issue and have made it possible to load jQuery without activating $(), making it possible to mix jQuery and Prototype in the same file:
jQuery.noConflict();
Although I'm not sure that it's a good idea to go into a project planning to mix JavaScript libraries, there are times when you might want to use a particular effect or widget, which is available in (for example) YUI, but not jQuery.
Like many other JavaScript libraries, jQuery comes with a set of visual effects that you can use on a page. We already have seen mention of show and hide, although each of these also can take an argument (slow, normal or fast, or an integer) indicating the speed at which the effect should run:
$('p').show('slow').css({'background-color': '#f00'});
Similarly, you can have elements hide and reveal themselves by sliding (slideUp and slideDown) or fading (FadeIn and FadeOut). And, of course, you always can modify one or more CSS attributes, as we saw in an earlier example, overriding their original settings.
It's easy to set an event handler in jQuery. For example, if you want to pop up an alert every time someone clicks on the button with an id attribute of mybutton, you would write:
$('#mybutton').bind('click', function() { alert("Hello, there!"); });
Because it is so common to bind an event handler to the click of a button, you can shorten it to:
$('#mybutton').click(function() { alert("Hello, there!"); });
The thing is, where do we put this event handler? We can't put it in the <head> of the document, because the <body> (in which the button presumably is contained) is not yet defined and available. We could assign it to a DOM handler, but there are issues associated with that. The jQuery method is both unobtrusive (as modern JavaScript should be), effective and cross-browser-compatible. We register an event handler for when the document is ready, and then put any event handlers we want in there:
$(document).ready(function() { $('#mybutton').click(function() { alert("Hello, there!"); }); }
If you put this in the <head> of your HTML file, jQuery will execute the function when the document is ready. This means by the time the HTML is rendered for the user, event handlers all will be in place. It is not uncommon for the invocation of $(document).ready() to contain the key JavaScript invocation code for a site, with long, complex functions placed in an external library.
Like other JavaScript libraries, jQuery also provides built-in support for AJAX (behind-the-scenes HTTP) requests. For example, we can make it such that clicking on a button sends an HTTP request to a server, grabs the returned HTML snippet and then puts that snippet in the user's browser window. To do that, we need an HTML file:
<html> <head> <link rel="stylesheet" type="text/css" media="screen" href="test.css"/> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> // JavaScript code here $(document).ready(function() { $('#mybutton').click(function() { $('#message-paragraph').load('blah.html'); }); }); </script> </head> <body> <h1>Test page</h1> <p id="message-paragraph">This is a paragraph</p> <p><input type="button" id="mybutton" value="Button" /></p> </body> </html>
In the head of the file, we have a standard call to $(document).ready, which assigns a handler to the click event on the button at the bottom of the page, whose id attribute is mybutton. The function, very simply, tells the paragraph (message-paragraph) to load the file blah.html from the same origin (that is, server) as the current page. The browser retrieves the file in the background, asynchronously, allowing the user to do other things while the contents of blah.html are retrieved and then stuck into the appropriate paragraph.
The above demonstrated that jQuery can retrieve HTML from an external file. But, jQuery can do more than that, retrieving not only HTML, but also XML and JSON (JavaScript Object Notation) over the network and then parsing it. We even can load a JavaScript file and execute it:
<html> <head> <link rel="stylesheet" type="text/css" media="screen" href="test.css"/> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> // JavaScript code here $(document).ready(function() { $('#mybutton').click(function() { $.getScript('blah.js'); }); }); </script> </head> <body> <h1>Test page</h1> <p id="message-paragraph">This is a paragraph</p> <p><input type="button" id="mybutton" value="Button" /></p> </body> </html>
Then, I create blah.js:
$('#message-paragraph').html("<h1>Boo!</h1>");
In other words, I've split the functionality from one file into two different ones. The difference is that the loaded file is treated as a program and is executed as such. So, when I click on the button, the contents of blah.js are loaded by jQuery, which then modifies the paragraph.
As I hope you've seen, JavaScript programming with jQuery is fairly easy and straightforward, and it allows us to do many things quickly and elegantly. Next month, we'll continue to look at jQuery, examining its plugin architecture and some of the widgets in jQuery's UI library.
Resources
jQuery is distributed from the Web site www.jquery.com. That site not only has software downloads, but also documentation, tutorials and links to various libraries and tools that many jQuery authors use.
I recently received two books on jQuery, both of which I found to be quite good. From Packt Press comes Learning jQuery by Jonathan Chaffer and Karl Sweebber, which is good for Web developers who have experience in another language already—perhaps even JavaScript. It reviews many of the different types of functionality a JavaScript programmer can accomplish using jQuery.
A new book that aims more for the basics is JavaScript: The Missing Manual by David Sawyer McFarland, published by Pogue Press and O'Reilly Media. This is a good book for JavaScript beginners, and it uses jQuery for many of its examples, particularly in the second half of the book.
Reuven M. Lerner, a longtime Web/database developer and consultant, is a PhD candidate in learning sciences at Northwestern University, studying on-line learning communities. He recently returned (with his wife and three children) to their home in Modi'in, Israel, after four years in the Chicago area.