Introduction
I have a Motorola Razr cellular phone, and I was sending some text messages one day, and was really impressed with their "autosuggest" feature. For those that don't know what I'm talking about, the phone will suggest words behind your text as you type. To insert the word, you just push up on the keypad. This makes it much easier to send text messages, and also ensures your spelling is correct. So, with that in mind, I set about to do the same thing, but for a web form. Sure, I've seen a lot of WinForms applications that have AutoSuggest, and I know there are some control sets out there that contain autosuggest drop down lists and textboxes (Anthem.NET Extensions have one that seems to work well, but you have to bind it to a database for the word lookup). I wanted something that required very little configuration, didn't require a database, but could still be customizable.
Enter the XMLHTTPRequest
object. I've written several articles concerning the use of it in AJAX based applications, and thought it would be well used here. The result is an ASP.NET (2.0) Web User Control that contains a textbox and a div
element that will display suggestions as you are typing text (see screenshot).
Using the Code
I'm going to go over the steps to incorporate this into your project. It's really pretty simple, and I'll add a final checklist at the end, in case you run into any problems.
Setting Up the Project
I've included all the code you'll need to get this running, and a sample dictionary. The word lists are far from complete, so you may want to remove a lot of the stuff in there, but this is just an example after all. The word lists are laid out in the form a.txt, b.txt, etc. Each text file contains words that start with a character from a-z. The reason I did this was to keep the XMLHTTPRequest
's size to a minimum. When you're in the textbox and you type "D", the request will only load the d.txt file and, consequently, all words that begin with the letter d. You'll need to make sure that the dictionary directory exists in the root of wherever you plan to use this control, since the JavaScript will look for dictionary/a.txt. You can easily open and modify these text files, since they're just comma delimited. Keep in mind that the more words you have, the slower the lookup will be, since it will have to load the whole library to look through and match the words.
You will need to make sure the directory (dictionary) and all of the files can be read, or you will get a permission denied JavaScript error.
Also included is an img directory. Be sure this is in your root as well, or, if you have a different folder, just modify the img
elements to point to wherever you decide to put them. There are only two images (up.png and loading.gif).
Using the Control
Once all the files are in place, just add the User Control to your web project. You'll be able to simply drag and drop the control on to your page. If you want to edit sizes and such, just modify the CSS in the control's HTML code-behind. I didn't include any properties since, as I said before, I wanted this to be able to run without any server-side scripting.
You'll see the control on the page, and it should be styled as in the screenshot above. That's it!
How it Works
We use the "onkeyup
" event of the TextBox
input to begin the process. Once the key is pressed, we just do a couple of checks. First, we want to see if the user has switched off AutoSuggest (by unchecking the checkbox). Next, we get the keycode. If it's the "up arrow" (code 38), we'll try to insert the current word into the textbox, as long as we have a word. Since we're going to nest the word inside an anchor tag (I wanted the user to be able to click the hyperlink as well as push the up arrow to insert), we'll get that object's innerText
property.
If we're getting a new word, we're going to set a timer using JavaScript's setTimeout
method. What this does is asynchronously fire the checkSuggest
method after 250ms. I did this because without an asynchronous call, the loading of the XMLHTTPRequest
actually paused the user from entering text into the textbox until the XMLHTTPRequest
was loaded, which was unacceptable to me. The checkSuggest
method just makes sure we're entering a "valid" character (a-z), and not a space, number, or punctuation mark.
function BeginSearch()
{
if (!UseAutosuggest())
return;
var keyID = event.keyCode;
if (keyID == 38)
{
var suggest = document.getElementById('suggest');
if (suggest.innerText == "No suggestions.")
return;
var link = document.getElementById('lnkWord');
var elem = document.getElementById('txtInput');
setText(link.innerText);
return;
}
Working(true);
var timerId = setTimeout(checkSuggest,250);
}
Once we're sure we have a valid character, the XMLHTTPRequest
is tasked with loading the word library and returning an array of words that fit the first letter and length of the word currently being typed. The JavaScript handles all the rest of the matching and displaying, so there is really no server side code required. You can copy the HTML, CSS, and JavaScript right out of the control and use it on any HTML page, stand alone. All that's required to configure server-side is read access to the word lists. The suggestWord
function takes the checkText
argument. We'll get the first character, and load the corresponding library.
var dict = "dictionary/" + checkText.charAt(0) + ".txt";
xmlhttp.open("GET",dict,true);
asynchText = checkText;
xmlhttp.onreadystatechange = MatchWords;
xmlhttp.send(null);
The MatchWords
callback function handles the response and parses the resulting text, trimming out any words that are shorter than what we input (if I put in "and", I shouldn't get a suggestion for "an"), then checking each word to see if it matches a word in our returned array. So, if I put in "app", I should get "apple" (as long as it's in the word list, if you use mine, you'll get "Appalachia").
var newSuggest = "";
var arLen=temp.length;
for ( var i=0, len=arLen; i<len; /> checkText.length)
{
newSuggest += temp[i] + ",";
}
}
Now that we have the words list (in an array), we're going to sort them, then start comparing them to our entered text. We just do this by looping through each character of the word until we get a non-match. If the match fails, we just move on to the next word in the list. If we reach the end of our input word, and we still have all matches, that has to be the right word.
function checkMatch(inputText, dictWord)
{
inputText = inputText.toUpperCase();
dictWord = dictWord.toUpperCase();
for (var x=0; x<inputText.length; x++)
{
if (inputText.charAt(x) != dictWord.charAt(x))
return false;
}
return true;
}
The rest of the JavaScript handles the styling and updating of all the requisite fields. If you're just planning on using this control in your website, it probably won't be terribly important to you. Just remember that the smaller the word lists are, the faster the autosuggestions will be.
Also of note, this control will handle multi-word inputs, so you could easy extend this out to a textarea input with the same functionality.
Installation Checklist
- Start a new ASP.NET Website (2.0)
- Unzip the AutoSuggest source
- Add the user control to your website project
- Add directories called "dictionary" and "img" to the root of wherever the control sits
- Add all files from the dictionary folder of the unzipped source into your dictionary folder (you can do this by adding files in the Solution Explorer)
- Add up.png and loading.gif to your img folder
- Drag the control to your page
- Build and execute
Also included in the release are the stand-alone HTML, CSS, and JavaScript files for testing without a website project. They can be found in the /html directory of the Zip file. You will need to move them to the same root as the dictionary and image folders.
Possible Upgrades
I'm a C# programmer, and I only dabble in JavaScript programming, so I'm sure the JavaScript is rife with inefficiencies. Please feel free to rip apart the JavaScript and post up here some possible improvements. As long as they're constructive, I'll be glad to make changes to the source. I did this for fun, and to demonstrate some possible other uses of the XMLHTTPReuest
object in UI programming.
Eventually, I'd also like to make the suggestions into a scrollable list. So, if I typed "app", I might get several suggestions like "apple", "apply", etc. Currently, this control only displays one suggestion at a time.
It is also important to realize that the code posted inside this article is composed of snippets. The full source is included with the download, so things like instantiating the XMLHTTPRequest
have been left out of this article.
Happy XMLHTTPRequest'ing!