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.