Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

AJAX Demystified - Part Four - The AJAX AutoSuggest Text Box

4.64/5 (11 votes)
21 Sep 2007CPOL7 min read 1   326  
Create an AJAX-based auto suggesting textbox or textarea with no database or server-side scripting needed.

Screenshot - AutoSuggestTextBox.jpg

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.

JavaScript
function BeginSearch()
{
    if (!UseAutosuggest())
        return;
    
    // If up arrow is pressed, insert the word

    var keyID = event.keyCode;
    
    if (keyID == 38) // Up arrow

    {
        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); //Show the working graphic


    // Use a timeout to help with input keying

    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.

JavaScript
// Load the library of words

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").

JavaScript
// Rule out all words that are less than the length of the text

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.

JavaScript
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!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)