Barack Obama had yet to be elected President of the United States, swine flu hadn’t taken hold, and Michael Jackson was still alive … when jQuery 1.3 was released. That sure makes it seem like a long time ago. So it’s no surprise that in that time, the jQuery team concocted a host of great new features and enhancements for the 1.4 release of the library.
Now that jQuery 1.4 has been out in the wild for a few months, and we’ve seen the 1.4.1 and 1.4.2 releases, I want to shine a light on the features about which I’m most excited. This isn’t a catalog of everything that’s new in the 1.4.x branch (for that, you should be checking the release notes); rather, it’s a run-down of my favorites: the ones I’ve started using extensively, or the ones that I think show the most promise.
Before we delve too deeply, let’s skim over a couple of fun, new (and, some might say, long overdue) API methods. Firstly, the delay
action. There must be hundreds of questions on the jQuery forum asking “How can I put a delay in my animation chain?” The answers were fairly ugly—you could fake it with animate
, or set up a JavaScript timer, or … some other horrible workaround. But no more! The delay
method accepts a regular jQuery duration parameter (that is, a number of milliseconds or one of the strings 'fast'
or 'slow'
), and simply waits before moving on to the next command:
$('p') .slideUp() .delay(2000) .slideDown();
Sweet. Next up, everyone’s favorite class-bending tool, toggleClass
, has been given a neat upgrade: you can supply multiple class
names (separated by a space) to be toggled. If the class
already exists on an element it will be removed, and if it doesn’t exist it will be added. This one can seriously clean up your navigation or accordion menu code.
And finally, another couple of useful shortcuts that will help improve the readability of your jQuery chains: first
and last
. These are part of the traversing category of jQuery methods, and will filter out all but the first or last elements of your selection:
$('p') .first() .addClass('first-paragraph') .end() .last() .addClass('last-paragraph');
The first
method is simply an alias for eq(0)
, and last
is an alias of eq(-1)
. Er, what’s that? Minus one? Yes. Another handy addition is the ability to supply a negative number to eq
to indicate a position starting from the end of the selection, rather than from the start.
If you plopped the jQuery1.4.2-min.js
file into your old project, you’d most likely find that everything keeps on working—which could lead you to suspect there’s nothing new worthy of your attention. But there are a couple of fantastic tricks that make excellent additions to your jQuery tool belt.
We all know that the best part of jQuery is its ability to chain actions together. So it’s a bit of surprise that one of the coolest additions in 1.4, quick element construction, is designed to reduce the amount of chaining when composing DOM elements from scratch:
$('<div/>', { id: 'myDiv', css: { backgroundColor : 'blue', padding : '5px' }, html: '<strong>My Div</strong>', click: function() { alert('clicked me!') }}).appendTo('body');
The new parameter, after our construction selector string, is an object containing the details we’d like to apply to the new element(s). It’s in the form of the familiar object literal—but in terms of its content, it’s quite peculiar. We can specify any attribute we want added to the elements and also specify a handful of jQuery properties and commands that will be automatically applied.
Above, we’ve added the css and html properties, and added a click hander: none of which are attributes for a div
element. jQuery uses some smarts to handle these internally and applies the correct results (search the source code for the occurrences of attrFn
if you’re interested in discovering everything you can specify).
The second big change you’ll want to pay attention to is the ability to set values with functions. This ability has been around before (for example, in the attr
function), but now it’s everywhere! css
, attr
, val
, html
, append
, wrap
, addClass
… most methods—where it makes sense—will now accept a function to set their values:
$('div').html(function(i) { return 'This is div number ' + i;});
And if that isn’t enough, there’s a second ingredient that makes setters even better: many setter functions also receive the current value of the item—which can be used inside your function without having to reselect the item:
$('a').attr('href', function(i, current) { return current + '?linkid=' + i;});
Here we’ve appended a query string value to the end of every link on the page—in a very terse and elegant manner.
A new release wouldn’t be much fun if weren’t given a few of new commands to play with, so let’s traverse some of the important API additions.
Before jQuery 1.4, selecting a subset of siblings generally required some careful chaining, or the potentially confusing slice
method. To help with this, we now have the groovy nextUntil
and prevUntil
methods that let us select all sibling nodes from the current selection to some specified end point.
In the following example, we’ll select the element with the id
first
, then each of its following siblings up to (but excluding) the sibling with the id
secondLast
. We’ve also included the optional second parameter, which filters the selection further. The net result is that we’ve selected all of the div
element siblings between #first
and #secondLast
:
$('#first') .nextUntil('#secondLast', 'div') .css('background-color', 'red');
prevUntil
works in exactly the same way, except that it selects elements that occur before the current selection, instead of after. Another new method in the same category is the parentsUntil
method. parentsUntil
will traverse the DOM up from the selected element, until it reaches an ancestor that matches the selector string passed in.
Sticking with new traversing methods, the has
method has been added to match its selector filter counterpart. The existing :has
filter accepts a selector string, and only returns elements that have children matching that selector:
$('p:has(.warning)').addClass('warning-parent');
In jQuery 1.4, we now have a method to do the same task in our jQuery chains:
$('p').has('.warning').addClass('warning-parent');
The last new method we’ll look at is the fantastically useful unwrap
command. The traveling partner of wrap
, unwrap
will remove the parents of a given selection of elements—leaving only the elements themselves. For example, if your page has a bunch of links that contains images, then the command $('a img').unwrap();
will remove the surrounding link tags, leaving just the images on the page.
jQuery conceals a lot of the hideously complicated JavaScript required to perform cross-browser DOM manipulation, but in doing so it’s often lead people to believe that it’s trying to be replace JavaScript. Nothing could be further from the truth: sure, you could stumble through adding simple effects with jQuery alone—but at some stage you’ll have to bite the bullet and get your JavaScript chops up to scratch.
jQuery 1.4 introduces a bunch of optional conventions and advanced features that are sure to make the seasoned JavaScript fan smile. We’ve already seen one with quick element construction. In a similar vein is the ability to bind multiple event handlers to different functions with a single object literal:
$('p').bind({ mousemove: function(e) { $(this).text('moved to:' + e.pageX + ':' + e.pageY); }, mouseout: function() { $(this).text('moved away.'); }, click: function() { $(this).unbind('mousemove mouseout'); }});
Like quick element construction, this technique allows you to circumvent the need for chaining. I’m sure that some jQuery users (like me) will love it, while others will hate it.
The live
functionality has been given a good overhaul, and finally works the way you’d expect: for all events. It’s also been complemented by a new method for working with event delegation: delegate
. delegate
is a way to attach event handlers to an element both when it is called and any time in the future when elements match the selector.
Sounds a lot like live
, doesn’t it? Yes, but there are a couple of key differences. Firstly, the delegate
method attaches to the element that you choose, whereas live
will bubble events up to a special container. By defining the element to which it binds, the code is more readable and more efficient. In the example below, we’ll bind to any current or future div
elements inside the #container
element:
$('#container').delegate('div', 'mousemove', function(e) { $(this).text('Moved to:' + e.pageX + ',' + e.pageY);});
The other advantage of delegate
is that, unlike live
, it has no problems binding to elements that have been selected using the jQuery traversal methods.
Right, moving on. If you’ve struggled to understand the concept of scope in JavaScript (or struggled to explain it to a co-worker), then there are a couple of new methods to help you. The proxy
method is a great bit of magic for people afraid of closures (or those who think they produce unreadable code). You can now bind your event handlers to a specified object, so that this
in the handler will refer to that object, rather than the element that fired the event. In the example below, we bind the controller.update
method to the paragraph’s click
handler. When it’s called, this
will be the controller
object—rather than the DOM element:
$('p') .click($.proxy(controller, 'update')) .mouseout(function() { // "this" is the paragraph element – as usual $(this).text('moved away.'); });var controller = { clicks: 0, update: function(event) { // "this" is the controller object - no closure required! this.clicks++; $(event.target).text('Number of clicks: ' + this.clicks); }};
If you liked proxy, you’ll love this one: jQuery 1.4 gives us the ability to specify an optional parameter in Ajax requests to set the context for callback functions:
$.ajax({ url: 'reset.html', context: controller, complete: function() { // "this" is the controller object! this.clicks = 0; }});
You can also set the context to be a DOM element, so that inside the callback functions you can write code like $(this).fadeIn()
and have it apply to the correct element automatically.
As I said at the outset, there’s much more to the 1.4 releases than the few features I’ve outlined here. If you’ve yet to do so, head over to the new API site and have a look at the release notes for 1.4, 1.4.1, and 1.4.2 to make sure there aren’t any nuggets of jQuery gold that you’ve missed.
It’s quite clear that the jQuery team and community certainly didn’t spend the last year sitting on their hands. They’ve been an unstoppable coding force—unleashing some huge performance gains and adding loads of cool new features.
But no matter how slick and shiny they are, it’s all for nothing if you leave it gathering dust on the CDN. It’s time to drop that JavaScript file in your next project and see what you can make it do.
Sporting a Masters in Information Technology and a lifetime of experience on the Web of Hard Knocks, Earle Castledine (aka Mr Speaker) holds an interest in everything computery. Raised in the wild by various 8-bit home computers, he settled in the Internet during the mid-nineties and has been living and working there ever since. As co-creator of the client-side opus TurnTubelist, as well as countless web-based experiments, Earle recognizes the Internet not as a lubricant for social change but as a vehicle for unleashing frivolous ECMAScript gadgets and interesting time-wasting technologies.