Ajax Makeover: Adding a Smart Type Ahead
[Jump to the demonstration page]
If you are like me, you probably have a hard time doing a realistic estimate
of the time you spend on any given task. That’s why Time Tracking
applications were invented… to help you manage and plan your projects
better. Unfortunately, their very existence collides with the way people
like to think and to work. Freely. Without the constraints of a ticking
clock. Making a web application that is actually helpful is going to
be quite a challenge for this makeover.
The first aspect of time tracking application I’m going to cover
is the task input. Chances are, there is a somewhat small set of tasks
that are part of your daily routine: deleting spams, writing status reports,
attending meetings, debugging code, etc… If you were able to make
an exhaustive list, you could populate a <select> field and that
would be your task input.
Of course (or hopefully), your job is not that predictable, and there are
lots of other way for you to spend your time at work. To describe these tasks,
you need a free text input.
The point of the type-ahead functionality (or auto-complete) is to combine
these two needs (predefined list and free text) in one field. The type-ahead
becomes ’smart’ when it learns from previous inputs and other
users and guesses your intent after just a couple keystrokes.
Before going into technical details, you may want to take a look at the demonstration
page.
A Basic Type-Ahead
The functionality core is similar to what Nicholas
C. Zakas presented at webreference.com. Here is a simplified outline
of the javascript implementation. Cross-browser considerations and advanced
unobtrusive techniques are intentionally
left out here, so be sure
to check out the final
implementation for a complete view of the code.
Creating an array of suggestions
var suggestions = ["deleting spam","attending meeting", "writing status report", "debugging code"];
Getting a reference on the task input field
var taskInput = document.getElementById('taskInput');
Capturing the key press event
taskInput.onkeyup = function (evt) {
if(evt.keyCode == 8 ) return; // no type-ahead on backspace
Finding a match in the suggestions array
for (var i=0; i < suggestions.length && suggestions[i].toLowerCase().indexOf(taskInput.value.toLowerCase()) != 0; i++);
if(suggestions[i]) {
Replacing the user input with the suggestion
var userInputLength = self.inputElement.value.length;
taskInput.value= suggestions[i];
And finally, selecting the added text
taskInput.setSelectionRange(userInputLength,suggestions[i].length);
}
}
Adding the Ajax Touch
Querying a suggestion service
We are going to load the suggestion array using an asynchronous call to
a ’suggestion service’ hosted on the server. The idea is to keep the
array short and accurate by querying the server whenever we fall short of
suggestions matching the user’s input.
if (!suggestionsArray[i]) {
var HTTPReq = new XMLHttpRequest();
HTTPReq.onreadystatechange = function() {
suggestions = HTTPReq.responseText.split("&");
}
HTTPReq.open("GET", typeAheadServiceURL + "?inputid="+encodeURIComponent("taskInput")+"&inputtxt="+encodeURIComponent(taskInput.value),true);
HTTPReq.send(null);
}
We are passing two values to the suggestion service: the name of the input
field, and the user input. The service responds with a list of suggestions
(separated by the ampersand ‘&’ character).
Feeding the suggestion service
Now, we want our suggestion service to learn from our user input, so whenever
the form is submitted we do a second call to the service, this time
using the ‘POST’ method.
var HTTPReqPost = new XMLHttpRequest();
HTTPReqPost.onreadystatechange = self.populateSuggestions;
HTTPReqPost.open("POST", self.typeAheadServiceURL, true);
HTTPReqPost.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
HTTPReqPost.send("inputid="+encodeURIComponent('taskInput')+"&inputtxt="+encodeURIComponent(taskInput.value));
The Suggestion Service will be presented in the next article. In the meantime
you can play around with the demo page and share your thoughts.
Update: The Type-Ahead functionality now includes a drop-down list of suggestions (’google-suggest’-type).
Update (7/29/2005): A newer version of the script is available.
May 5th, 2005 at 7:07 pm
This looks pretty nice … although to be honest, I’ve always hated the UI of this type of autocomplete. It makes it very difficult to enter something that’s a substring of something that’s autocompleted … it can “surprise” you by suddenly changing the input to something else.
What works for me better is a google-style autocomplete, with a dropdown that you can select from.
May 5th, 2005 at 9:07 pm
Good point Steve… On the other hand switching from typing text to selecting in a list also slows you down.
I think it comes down to: do you know what you want to type ? or do you want to get several suggestions first ?
The Type-Ahead works best in the first case. Sure, if you need a substring of the auto-completed text, you need to write it all and hit delete, but eventually the system will learn which one you use more often and auto-complete with it.
May 9th, 2005 at 9:13 am
Well Steve, after all I went ahead and implemented the complete ‘google suggest’ experience… Check out the demonstration page.
May 9th, 2005 at 4:27 pm
The new suggest UI implementation is much better. One thing: now you have to use the mouse. Google’s implementation allows you to use the up/down keys to traverse the selections and the enter to key to select it. However, this should ideally be added in addition to what you already have.
One other advantage your implementation currently has is that it doesn’t interfere with copying and pasting, which I find Google’s implementation does. (You cannot copy into a field — doing so clears the field’s value)
May 9th, 2005 at 7:55 pm
Bruce, I did implement the up & down keys… It should work fine with Firefox and IE. I haven’t tested with Safari and Opera 8 yet. What browser where you using ?
May 10th, 2005 at 1:35 am
One bug:
It doesn’t look like you show the updated choice list if someone types backspace.
In other words, the selection doesn’t grow as the user is removing letters that otherwise would narrow it down to a smaler set…
May 10th, 2005 at 2:55 am
Thanks Enrico.. I’ll fix that asap.
May 10th, 2005 at 3:39 am
Alright, the backspace and delete keys now reloads the suggestion list.
May 10th, 2005 at 5:52 am
Hmm. It appears to work just fine! Must have been user error before! Lol. Great implementation
May 31st, 2005 at 9:02 pm
I noticed that pressing enter “resets” the field, is this the correct functionality or should it fill the field with the currently selected value.
For example press “a” attending meetings will come up. Since this is the correct suggestion I press enter. It then resets the field to “”. I think it should fill the field with “attending mettings” instead of reseting its value. Your thoughts?
Using Firefox 1.0.4 in WinXP
May 31st, 2005 at 9:29 pm
Abraham.. pressing enter submits the form (which is the normal behavior). It looks like it is being reset, but it just reloads the form… it’s obviously bad usability design.. I’ll try to fix that asap.
May 31st, 2005 at 11:24 pm
Cedric, Thanks for the quick response. I love what you are doing here, I think its great stuff. I think having it bubble up to submit the form is not a great idea. The user might have other fields to complete.
Take a look at this example: http://wick.sourceforge.net/wick_sample/ (ajaxish as well)
I’ve used the more traditional jsrs drop down.. http://www.ashleyit.com/rs/jsrs/select/php/select.php and seems to work well.
June 3rd, 2005 at 1:20 am
Good work Abraham!
It is almost what I was looking for. The only thing missing is a down arrow button, that will display the full list. If we want to use it as a regular drop down list. If we don’t know what is inside the list.
And maybe scrolling bar when the list is bigger than a maximum size….
January 30th, 2006 at 7:15 am
Hello,
I’ve been pulling my hair out trying to get a working demo of the Smart Type Ahead code. Do you have an HTML/PHP page that uses the new code from 7/29/05?
Thank you!
Nelson
January 30th, 2006 at 9:18 pm
Nelson, the updated code samples are listed in this post.
If you can pinpoint the problem, email me at cedric at formassembly dot com.
July 20th, 2006 at 8:45 pm
How do you use autocomplete with an existing menu so that the user instead of scrolling down enters text which is then interpreted from the existing menu and suggestions are provided based on the menu.
August 8th, 2006 at 10:42 am
unable to view either the demo or the code………