j-j-j-jQuery. It’s on everyone’s lips, right? You love it or you hate it, or you’ve never tried it but you love it, or you’ve never tried it but you super-hate it. Yeah, we know.

Well, PJ and I launched FamSpam a bit ago and made the bold move of powering all the jabbascript with jQuery. We even wrote our own Facbeook-style lightbox library in jQuery (Facebox). So while this is a Ruby blog, indulge me for a moment as we dance with Ruby’s ugly-cool half-sister: Javascript.

whatQuery?

There are a bajillion posts about jQuery, all of which introduce you gently, so I will be brief: jQuery is all about a single namespace and kickass querying. (Get it?)

Our buddy Hpricot, you may remember, was heavily influenced by jQuery’s selector syntax. Which was, in turn, heavily influenced by CSS selectors. As such, some of this may look familiar:

$('#id').hide() $('.class').css('height', 20) $('#posts li > a').addClass('dark')

And so forth. One of the fun things is that any of those $() queries may return 0, 1, or more elements—yet the code stays the same. That’s right: our css() call would affect the height of all matched elements. Same with the addClass. But, if nothing is found, it’ll all silently fail. jAwesome!

niceQuery()

While some of the recent “jQuery vs <insert_framework_here>” blog posts might not be so nice, jQuery itself certainly is: it (mostly) easily works alongside other libraries. That means you can start dipping your toe into the jSauce while your Prototype or MooTools code doesn’t suspect a thing.

It’s easy:

jQuery.noConflict()

jQuery('#id').hide() jQuery('.class').css('height', 20) jQuery('#posts li > a').addClass('dark')

My above examples would now be written like this:

The noConflict() call causes jQuery to defer ownership of $() to Moo or Proto, leaving your current js intact. How thoughtful. Check more at the comprehensive doc site.

chainQuery()

jQuery is all about chaining, in a big way. Here’s an example from FamSpam:

var person_email = $(this).parent().find('#person_email').val()

Pretty self explanatory. The find is scoped to the receiver, in this case the parent of the current element.

Another cool chain:

$('#invite_error').show().text('Please enter an email and a name.')

Hrm, we should probably put text() before show(), yeah? I love these kind of questions!

Finally, a slightly more advanced chain:

$('#facebox .body').children().hide().end(). append('<div class="loading"><img src="'+$s.loading_image+'"/></div>')

Get it? The end() reverts the most recent ‘destructive’ (read: find) operation. So we start with the .body, then find its children, then hide its children, then go back to .body and append some html. Slick, I think. Real slick.

Like I said, the doc site is super great.

ujsQuery()

Okay, here’s the segue: jQuery has unobtrusiveness built in. And it feels smooth. Real smooth.

Here, a snippet straight from FamSpam’s javascript:

$('.reset_invite_form').click(function() { $('#new_person').resetForm() $('#invite_another').hide() $('#invite_another > span').remove() $('#new_person').show() return false })

Pretty simple, right? And clear, to boot. What we do is slip this code inside of a function passed to $(document).ready(), which will be run when the, erm, document is, uh, ready.

$(document).ready(function { $('.reset_invite_form').click(function() { ... stuff ... }) })

Like this:

So on and so forth. We attach Facebox to links the same way:

if ($.facebox) $('a[rel*=facebox]').facebox()

If the Facebox plugin is loaded, we find any links with a rel of “facebox” and convert them from normal links into jsery’d Facebox links. Easy as pie.

Which brings us, of course, to the segue.

spamQuery()

How are we using jQuery on FamSpam? jRails? Something custom? By hand?!

Yeah, well, by hand. We add all our behavior unobtrusively using the method detailed above. As far as I know, there’s no javascript in our html. If there is it’s on the run. For its life.

If you want to peep around, the js is (predictably) right here: http://famspam.com/javascripts/application.js.

Something to note: as of writing (1.2.2), jQuery doesn’t play nicely with Rails’ respond_to. But, hold the phone, it’s okay: a simple fix. Right here:

jQuery.ajaxSetup({ 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")} })

You’re now ready to rock.

Oh, one more thing before we move on: if you want some ajax-flavored will_paginate, check out this short guide. It was mentioned in another post, and now it’s mentioned here.

plugQuery()

jQuery, you see, has a wonderfully simple plugin system. We take full advantage of it by using a few choice plugins. Here’s a taste to wet your pallet.

The most essential plugin is the jQuery Form Plugin. With it, you can unobtrusively convert normal forms into ajax forms. The (obvious) advantage of this is graceful degradation, which is very kind but also very courageous.

$('#new_person').ajaxForm(function() { alert('Atta boy!') })

Seriously. Simple. And just so perfect for Rails—all the form’s attributes stay the same, including its action and method, just now it’s submitted through ajax. respond_to and jQuery are so in love it’s making me sick.

Another plugin we use is the Tablesorter. While we don’t have much tabular data on the promo or family sides of FamSpam, our admin interface is full of it. Want to sort your families by number of members? Conversations? Photos? It’s one line of code with this plugin. Sure, we’ll have to do some more complicated server-side sorting as our database grows, but this does the trick so quick right now.

$('#sorted_table').tablesorter()

See?

Another plugin we really love is the anti-aliased rounded corner plugin. Unfortunately this is not the most popular rounded corner plugin for jQuery, and that’s a shame. A damn shame. Because it’s definitely the best. We use it on the home page and other places we thought could use some class.

As usual, it’s dead simple once installed:

$('.corner').corner()

You don’t have to be so generic with it, but we like to be.

Finally, the brand new autocomplete plugin by ReinH and wycats is simple, small, and slick. See a pattern here? We’re using this on our admin site and couldn’t be happier. It speaks JSON, baby. Sign me up.

thatsitQuery()

Thanks for letting us stray for a moment from our normally dreary discourse. Got any other cool jQuery tips or treats? Leave ‘em in the comments.

Oh, a parting gift. More code to chew on: our tour.js. We use it to power the FamSpam tour. Enjoy.