Ajaxariffic Autocomplete with Scriptaculous

You’ve read the ONLamp tutorial, but you lust for more. So you want to autocomplete, do ya? Do ya??

You’ve come to the right place.

        <span id="more-3930"></span>

Into JavaScript? Have I got good news for you!

If you’re interested in JavaScript-driven web apps, snazzy visual fx, and generally confusing people into thinking your site is Flash—but oh-so-much better—you should buy our JavaScript Performance Rocks! book while it’s still in beta. Written by Thomas Fuchs, the creator of Scriptaculous, and yours truly, the maker of funny jokes and shiny graphics.

We cover everything from The Most Ridiculous Performance Fix Ever (and it is ridiculous), to serving strategies, DOM diets, loop unrolling (for those really extreme cases), how to play nice with the garbage collector, and everything in between. And it comes with our custom profiling tool, The DOM Monster, which analyzes your pages and suggests fixes. This package is only $24 right now but will be $29 as soon as it’s done, in mid-June 2009… but if you snag your copy today, you get the final version by email just as soon as it’s ready and save a noteworthy 5 bux! You can’t lose.

Autocompletin’ in Rails

With the magic of Prototype.js and Scriptaculous, the autocomplete is, in theory, extremely easy. But throw a lack of good documentation into the mix and something easy and “magical” and Bad Things Happen.

First Things First

One, check out the autocomplete demo. It’s one of the more “magical” Ajax goodies because it automatically handles the appearance of the floating div, the keyboard navigation, the ability to click your choice with the mouse or use Tab or Enter to complete your entry.

Is that what you want? If not, you’ll need to find another solution, because this stuff’s all built in—you can’t do an autocomplete with this code and get it any other way (although you can style it differently, to be sure). The pixie dust is non-negotiable.

Secondly, you’ll need to get the very latest version (download link) of the Scriptaculous script files and also their patched version of Prototype.js. If you’re using older versions of either software and having problems, this may be the reason.

The Simplest Autocomplete

You can almost scaffold autocompletion, as you can see in this very simple demo (also an official Scriptaculous demo). If you don’t want to do anything fancy, this may be the way to go. At least you can see near-instant results this way.

The source for this is:


# view
<%= text_field_with_auto_complete :contact, :name %>

# controller
auto_complete_for :contact, :name

In the view, you’re using the built-in Rails helper text_field_with_auto_complete, which takes two arguments: a symbol for the model and a symbol for the method (column) of the model you want to autocomplete on.

Other examples of this helper might be:

<%= text_field_with_auto_complete :book, :title %>
<%= text_field_with_auto_complete :user, :username %>
<%= text_field_with_auto_complete :user, :email_address %>

This not only does some Ajax magic, sending an Ajax request to your controller, but it creates a field appropriate for Rails use when creating or editing an instance of a given model, just like a normal form helper.

In the controller, you’re using the method auto_complete_for which, surprisingly, takes exactly the same arguments as the widget in the view. Hey, that’s not all that tough at all.

It probably goes without saying that you’ll need to be working off a database model with actual, you know, content in it for this to work. But I guess it really doesn’t go without saying since I just said it. Oops. There goes that idea.

Mr. Ajax Fancypants

Of course, once you taste the hors d’oeuvres (can I buy a vowel? what do you mean, we’re out?), your tummy starts grumbling for dinner. Man cannot live on miniature quiches alone.

There are just a few rules you need to know about the Rails magic in order to create your own fancypants autocompletes to inspire those oohs and ahhs.

The View

If you’re wanting to provide autocompletion for a field that belongs to a model, for example in an add or edit screen, you’ll want to use the same old helper in the view as you would for the dead-simple autocomplete:


# view
<%= text_field_with_auto_complete :cookie, :flavor %>

If you want to do something like a live search, see the heading “Roll Your Own” a little further down.

Be Controlling

When you don’t wanna go straight to the model for the dish, you’ll want to avoid the scaffolding and write your own method in the controller. There’s some magic here, too, since Rails is going to expect a method called auto_complete_for_cookie_flavor—the last two items being the arguments you gave to text_field_with_auto_complete. Phew.

To take a nod (and some slightly modified code) from Scriptaculous, here’s what you might do in your controller:


def auto_complete_for_cookie_flavor
  @cookies = Cookies.find(:all,
    :conditions => [ 'LOWER(flavor) LIKE ?',
    '%' + params[:cookie][:flavor].downcase + '%' ],
    :o rder => 'name ASC',
    :limit => 8)
  render :partial => 'cookies'
end

As you can see, auto_complete_for_cookie_flavor is a custom controller method which searches for cookies matching the flavor the user has been in the process of typing. This method will get called every time someone presses a key in the cookie flavor autocomplete field so the result will get ever more filtered. Sweet.

I’m Rather Partial to Lists

But we’re not done yet… you need to have that cookies partial. And it has to be crafted a certain way, because the Javascript powering all the magic is very particular.

Here’s what the view partial might look like:

# filename: _cookies.rhtml
<ul class="cookies">
<% for cookie in @cookies do -%>
  <li class="cookie">
    <div class="image">
    <img src="/images/cookie/<%= cookie.id.to_s[-1,1] %>.jpg"/>
    </div>
    <div class="name"><%=h cookie.name %></div>
    <div class="flavor">
      <span class="informal"><%=h cookie.flavor %></span>
    </div>
  </li>
<% end -%>
</ul>

This is because the Javascript expects only a UL—an unordered list—and its contained list items (and you have to make sure to write good XHTML and close all your tags, including <li></li>). So anything fancy that you can do within the confines of the list item tags, you can probably get away with.

If you need more help, load up your site in FireFox, play with the autocomplete for a second or two, then open the DOM Inspect from the Tools menu. It’ll show you the autocomplete div even if it’s currently hidden, and you can find out the class names and ids of any contents.

Roll Your Own

If you want to work off a field that does not belong to a column in one of your models, or don’t want the drop-down/keyboard nav/tab completion magic, you will want to use auto_complete_field instead, like thus:

<input type="text" name="snacks">
<div id="snacks_auto_complete"></div>
<%= auto_complete_field 'snacks', :url => {:action => 'complete_me'} %>

The auto_complete_field method lets you specify your own controller and method to get the autocomplete results, and it automatically assumes you want the data to be populated in a div or other HTML element with the id that equals the name of the input field plus _auto_complete.

Remember that this won’t provide all the fancy auto-magic with the drop-down div and select stuff. But it also means you can craft a response in any format you like, not just a UL.

Stylin’

Whether you use the fancy custom goodies above or the original easy-peasy scaffolding, you’re never quite done til everything looks gorgeous and high-tech and Web2.0-worthy. But your list will look like—I’m just going to be blunt here—crap if you don’t use the powers of CSS. You may not even be able to see your autocomplete results because they might not be floating on top of your content, as they’re supposed to.

Here’s some sample CSS that I, uh, borrowed from Scriptaculous’ demo. This doesn’t cover the above fancy stuff, but it will get you started, because anything you output will get wrapped in a div called autocomplete and there are other things you can count on, such as the list item that your user is currently on—whether via keyboard arrow keys or mouse movement—being given the class selected.

<style type="text/css">
    div.auto_complete {
      position:absolute;
      width:250px;
      background-color:white;
      border:1px solid #888;
      margin:0px;
      padding:0px;
    }
    li.selected { background-color: #ffb; }
  </style>

53 Comments

  1. I was very dissapointed of this…

  2. [...] Slash7 tutorial on Ajaxariffic Autocomplete with Scriptaculous was helpful, but it is a bit outdated, considering that it is from [...]

Hey, why not get a shiny
Freckle Time Tracking
account?