Using Autocompleter Autocompleter comes in two flavors. One, named Autocompleter.Local, keeps an array of possible suggestions for instantaneous feedback. The other, Ajax.Autocompleter, relies on a remote server to give it suggestions—making an Ajax call whenever suggestions need to be retrieved. Naturally, Autocompleter.Local has less overhead, since it does not need to talk to the server; as a result, its suggestions will usually appear far more quickly. You’ll only want to fall back to Ajax.Autocompleter if the pool of suggestions is simply too large to keep on the client side, or if the logic for picking suggestions is more complicated than an ordinary string match. We’ll cover these cases several pages from now, but for now let’s use the local version for simplicity’s sake. Using Autocompleter.Local The syntax for declaring a new Autocompleter.Local is new Autocompleter.Local(inputElement, updateElement, array, options); where inputElement is the text box, updateElement is the element that will hold the sugges- tions, array is the list of possible suggestions , and options is the configur ation object we’ve come to know so well. Let’s add a script tag to the page and declare an Autocompleter.Local on page load: <script type="text/javascript"> document.observe('dom:loaded', function() { new Autocompleter.Local('player_name', 'player_suggestions', ['James Polk', 'James Buchanan', 'Franklin Pierce', 'Millard Fillmore', 'Warren Harding', 'Chester Arthur', 'Rutherford Hayes', 'Martin Van Buren']); }); </script> Our array contains a short list of nonnotable American presidents—the benchwarm- ers of our fictional league. Rather than make the user choose from an endless drop-down menu or force her to remember how many ls are in Fillmore, Autocompleter will offer pos- sible name completions after only a few keystrokes. Save index.html and open it in a browser. You’ll see a text box, of course, as shown in Figure 12-1. CHAPTER 12 ■ ADVANCED CONTROLS: AUTOCOMPLETERS, IN-PLACE EDITORS, AND SLIDERS 279 Figure 12-1. The autocompleter in its ordinary state There’s more going on here than would appear. Bring up the Firebug pane and move to the HTML tab (see Figure 12-2). Figure 12-2. Firebug’s view of the panel that will hold our suggestions Two things have already happened. Our container div is hidden; it won’t appear until it has at least one suggestion to present. But expanding the div shows that there’s now an empty ul inside. Let’s put that div to work. Click the text box and start typing the name “James.” You won’t even need to finish the name—two suggestions will appear before you’re done (see Figure 12-3). Figure 12-3. Two possible completions appear. CHAPTER 12 ■ ADVANCED CONTROLS: AUTOCOMPLETERS, IN-PLACE EDITORS, AND SLIDERS280 You should notice two things. First, the list of possible suggestions is populated dynamically by Autocompleter. When there is at least one match from the suggestion bank, the container div is shown and its child ul is filled with one list item for each match. When there are no matches, the container div is hidden, and its child ul is stripped of all its items. Second, the list looks awful. It doesn’t even look like a menu. There’s no affordance, nothing that says, “I can be clicked.” But that’s by design. Autocompleter constructs the HTML for your list, but leaves the styling up to you. Look at the HTML tree in Firebug to see what I mean: <div id="player_suggestions"> <ul> <li class="selected"> <strong>Jame</strong>s Polk </li> <li> <strong>Jame</strong>s Buchanan </li> </ul> </div> So we know that the individual choices are list items, and that the “active” choice will have a class name of selected. A portion of each choice is wrapped in a strong ele- ment, highlighting the substring that matches what you’ve typed. As you type more characters, the strongly emphasized part of the phrase will grow. We need to style this HTML to look more like the drop-down menus that users are familiar with. It needn’t look exactly like a native drop-down menu, of course, but it should resemble one enough that a user can recognize its purpose. Add a style tag in the head of index.html: <style type="text/css"> body { font: 67.5% "Lucida Grande", Verdana, sans-serif; } /* a thin border around the containing DIV */ #player_suggestions { border: 1px solid #999; background-color: #fff; } CHAPTER 12 ■ ADVANCED CONTROLS: AUTOCOMPLETERS, IN-PLACE EDITORS, AND SLIDERS 281 /* get rid of the bullets and un-indent the list */ #player_suggestions ul { list-style: none; margin: 0; padding: 0; } #player_suggestions li { padding: 2px 3px; } #player_suggestions strong { font-weight: bold; text-decoration: underline; } /* the "active" item will have white text on a blue background */ #player_suggestions li.selected { color: #fff; background-color: #039; } </style> The devil is in the details when you’re trying to make styled HTML look like built-in controls and widgets (see Figure 12-4). If we wanted to do something more elaborate, we could replace the selected item’s background color with a background image—one that has a slight gradient—to give the item some texture (as an homage to Mac OS X). Or we could decrease the opacity of the menu itself, matching the transparency of Windows Vista’s pull-down and drop-down menus. It’s up to you. HTML is your canvas and you’re Bob Ross. Figure 12-4. CSS makes the list of suggestions look more like a native control. Time to see what this thing’s made of. Bring focus to the text box and start typing “James” once again. Experiment with the several ways you can choose from the menu: CHAPTER 12 ■ ADVANCED CONTROLS: AUTOCOMPLETERS, IN-PLACE EDITORS, AND SLIDERS282 • Click a suggestion. • Use the up/down arrow keys to highlight a suggestion, and then press Enter. • Use the up/down arrow keys to highlight a suggestion, and then press Tab. Now try several ways to dismiss the menu: • Click outside of the text box or move focus somewhere else with the keyboard. • Press the Escape key. • Finish typing the desired choice. For example, if you type “James Buchanan,” the menu will disappear as you type the final n, since there’s no more completing to be done. When a user recognizes our list as a drop-down menu, he’ll expect it to act like one. For the user’s sake, Autocompleter tries very hard to ape the behavior of a drop-down. Robust Autocompleter, the Ajax Version The more robust version of Autocompleter is Ajax.Autocompleter. Rather than store the suggestion bank locally, it gets a list of suggestions from the server. This approach has two large advantages: • Autocompleter.Local does a simple text match against the string. In an autocom- pleter that suggests US cities, when I type “New,” I’ll get offered “New Orleans” and “New York” (among others) as suggestions. But when I type MSY, the airport code for New Orleans (as can be done on many travel sites), I receive no suggestions. The logic that matches an airport code to a city is beyond the scope of Autocompleter.Local. Ajax.Autocompleter punts on that logic. It tells the server what the user typed and accepts whatever is returned. On the server side, I can do a more complicated match—I can search for string matches against city names, airport codes, or any other identifiers I choose. • Ajax.Autocompleter makes perfect sense when dealing with humongous data sets. In our case, we’re pulling from a small list, but a professional football league has around 30 teams and 53 active players per team—roughly 1,600 players. It’s possi- ble to use Autocompleter.Local with such a huge data set, but do y ou really want to place a 1,600-item array in your page and transfer it over the pipe? CHAPTER 12 ■ ADVANCED CONTROLS: AUTOCOMPLETERS, IN-PLACE EDITORS, AND SLIDERS 283 To demonstrate Ajax.Autocompleter, we’ll first need to write a script that can return suggestions when it’s called via Ajax. ■Note For this part, you’ll need to be running a web server (either locally or remotely) that supports PHP. Naturally, the concept is similar for other server environments. Create a file called autocomplete_players.php in the same folder as your index.html file: <?php // For this sample script we'll use another array; in a // real-world app, we'd probably search a database instead. $suggestions = array( 'James Polk', 'James Buchanan', 'Franklin Pierce', 'Millard Fillmore', 'Warren Harding', 'Chester Arthur', 'Rutherford Hayes', 'Martin Van Buren' ); $value = isset($_REQUEST['player_name']) ? $_REQUEST['player_name'] : ""; $matches = array(); foreach ($suggestions as $suggestion) { // Look for a match (case-insensitive). // If found, wrap the matching part in a STRONG element, // wrap the whole thing in a LI, // and add it to the array of matches. if (FALSE !== stripos($suggestion, $value)) { $match = preg_replace('/' . preg_quote($value) . '/i', "<strong>$0</strong>", $suggestion, 1); $matches[] = "<li>${match}</li>\n"; } } // Join the matches into one string, then surround it // with a UL. echo "<ul>\n" . join("", $matches) . "</ul>\n"; ?> The output of this PHP script is the literal HTML to be inserted into the page. CHAPTER 12 ■ ADVANCED CONTROLS: AUTOCOMPLETERS, IN-PLACE EDITORS, AND SLIDERS284 . SLIDERS282 • Click a suggestion. • Use the up/down arrow keys to highlight a suggestion, and then press Enter. • Use the up/down arrow keys to highlight a suggestion, and then press Tab. Now try several. menu itself, matching the transparency of Windows Vista’s pull-down and drop-down menus. It’s up to you. HTML is your canvas and you’re Bob Ross. Figure 12-4. CSS makes the list of suggestions. focus to the text box and start typing “James” once again. Experiment with the several ways you can choose from the menu: CHAPTER 12 ■ ADVANCED CONTROLS: AUTOCOMPLETERS, IN-PLACE EDITORS, AND