Web designers must always keep usability in mind when designing web sites. A site must allow quick and easy access to information during the very short time that a site first holds a visitor's interest. Any confusion that ensues about where things are, and that person's business is gone. Providing a way to precisely search for what they need is an excellent way to provide that usability. What Chris Root explains in this article is a way for your visitors to find and select items contained in long lists. He will also suggest ways to expand this to searching within HTML or XML documents.
Auto-Complete
Many desktop applications have user interface controls that allow a user to find matches for things as they type. This feature can be very useful for long lists of items such as states, countries, streets or product categories. Many web browsers implement this sort of functionality in their address bars. As you type, web site address matches that are part of a list of recently visited sites appear in a menu below the address bar. This reduces the amount of time it takes to access information.
Another place this is implemented is in HTML select menus. Unfortunately this only works with the first letter typed, it is not implemented in all browsers on all platforms and it doesn't shorten the list of choices to only matches.
The script described in this article will allow a user to begin typing what they are looking for in a text box while a select menu updates itself with matches. In the example the list comes from the contents of the select menu but it can also come from other sources.
The HTML
The HTML for this project is pretty simple. You could however use this script several places in a large form with multiple lists of information with no trouble. This example uses a list of city streets.
<body onLoad="fillit(sel,entry)">
<div>Enter the first three letters of a street and select a match from the menu.</div>
<form><label>
Street
<input type="text" name="Street" id="entry" onKeyUp="findIt(sel,this)"><br>
<select id="sel">
<option value="s0001">Adams</option>
<option value="s0002">Alder</option>
<option value="s0003">Banner</option>
<option value="s0004">Birchtree</option>
<option value="s0005">Brook</option>
<option value="s0007">Cooper</option>
<!--and so on and so forth-->
</select></label>
</form>
</body>
</html>
When the text box registers a keyUp event, the find() function calls and passes two parameters, the id of the select menu and a reference to the text field.
For something like state information, allow the user the choice of using the auto-complete script or just selecting something from the menu, especially if they know the item they wish to select is at the top of the list. If someone lives in Alabama for instance, there is no need to have them enter the first three letters of their state when the item they want is at the top of the list of states. Fill the select menu (a list box can be used as well) with all the values and text labels that you want your user to choose from in the HTML code to start with.
Alternatively, depending on the information in the list, the choice may not be as obvious. In this case you could store it in an array only and the user would always need to select a match. If there was only one match, and that match was the correct one, they could leave the menu alone. Otherwise they would need to select from the available matches displayed in the menu.
The longer the list the more useful our script becomes. It has been tested with a list over 1000 city streets and had an acceptable performance, even on a not so modern machine. There is a minimum of two characters before a search will start. this helps reduce the number of matches shown after any given keystroke. This limit can be adjusted easily.
When the page loads, a function called fillit() is called.
//initialize some global variables
var list = null;;
function fillit(sel,fld)
{
var field = document.getElementByid(fld);
var selobj = document.getElementById(sel);
if(!list)
{
ar len = selobj.options.length;
field.value = "";
list = new Array();
for(var i = 0;i < len;i++)
{
list[i] = new Object();
list[i]["text"] = selobj.options[i].text;
list[i]["value"] = selobj.options[i].value;
}
}
else
{
var op = document.createElement("option");
var tmp = null;
for(var i = 0;i < list.length;i++)
{
tmp = op.cloneNode(true);
tmp.appendChild(document.createTextNode(list[i]["text"]));
tmp.setAttribute("value",list[i]["value"]);
selobj.appendChild(tmp)/*;*/
}
}
}
A global variable is initialized to null. This will hold an array that in turn holds two custom objects to hold our data. We then get a reference to our select menu and text field objects. If our array does not exist yet (the page has just loaded so it’s still null), then we get the number of options in our select menu, set the contents of the text field to empty and begin looping through the menu contents.
As we run through each menu option, an object is created that will hold both what is in the value attribute and the text of the option tag.
If however our list array already exists, we are calling the function in order to refill the menu with all the original data. An option element is created and a temporary container is initialized.
In the loop the select menu is reconstructed using DOM methods.
Finding a Match
The findIt() function does the searching. It accepts two arguments. The first is the name of the select menu, the second is the name of the text field.
function findit(sel,field)
{
var selobj = document.getElementById(sel);
var d = document.getElementById("display");
var len = list.length;
if(field.value.length > 2)
{
if(!list)
{
fillit(sel,field);
}
var op = document.createElement("option");
selobj.options.length = 1
var reg = new RegExp(field.value,"i");
var tmp = null;
var count = 0;
var msg = "";
for(var i = 0;i < len;i++)
{
if(reg.test(list[i].text))
{
d.childNodes[0].nodeValue = msg;
tmp = op.cloneNode(true);
tmp.setAttribute("value",list[i].value);
tmp.appendChild(document.createTextNode(list[i].text));
selobj.appendChild(tmp);
}
}
}
else if(list && len > selobj.options.length)
{
selobj.selectedIndex = 0;
fillit(sel,field);
}
}
The first step is to get references to the select menu and the text field. We also need the length of the list array.
If the number of characters in the text field is greater than 2 and the list array exists. Then the menu is cleared of it's content to prepare it for display of any matches. The number of options is set to one rather than 0 to allow for an option that is always there such as a “Select a Street” option.
A regular expression object is then created that will be used to look for a match at the beginning of a given string. Using this object to create a regular expression allows the use of a string from whatever source we wish to be used along with any regular expression characters. The first parameter in the object constructor is the regular expression the second is any flags such as "i" for making the search case insensitive. If you were searching something other than one or two word street names, state names or country names you would want to match the beginning of word boundaries using "\b" instead of "^".
A few utility variables are initialized and we then loop through each of the list items contained in the arrays. If there is a match, the values are used to fill a new copy of the option element we created before the loop started. One thing to note about setting the properties of option elements is that the text label of an option is not an attribute. You must use the optionelement.text syntax rather than setAttribute to set the text label for each option.
If the length of the text in the field is less than 2 characters then we need to determine if the list needs to be refilled with all the values. By doing this, you allow the user to give up on their search before typing more than two characters and manually select something from the menu if they wish. If the user selects the text in the field and clears it to start a new search this will trigger that action. The fillit function is called and the select menu is refilled.
Possible Mods
To make this script and user interface more like the auto-complete widget in a browser address bar, you could use a DHTML menu and provide keyboard control for selecting a match and updating the content in the text box with the selected match.
This script would allow searching in any array of information and with a little modification any HTML collection. Searchable FAQ's, API documentation or help systems could be achieved by searching content contained in a hidden IFrame, the main HTML document itself or an XML document loaded in the background using the HTTPRequest object.
Conclusion
As you can see using auto-complete widgets on a web site can allow a visitor quick access to information. Always be on the lookout for ways to improve the user experience for your visitors and they will continue to come back for more.
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |
More JavaScript Articles
More By Chris Root
developerWorks - FREE Tools! |
<a href="http://zeus.developershed.com/shonuff.php?blackbird=3853&zoneid=442&source=&dest=http%3A%2F%2Fwww.ibm.com%2Fdeveloperworks%2Fspaces%2Fjazz%3FS_TACT%3D105AGY31%26S_CMP%3DDEVSHED&ismap="><img src="http://images.devshed.com/corp/img/news/jazz01.gif" alt="developerWorks Jazz space" align="left"></a>You've heard the buzz about Jazz... want to know more about it from a developer's perspective? Check out the Jazz space on developerWorks. This space is an up-to-date resource for developers, including technical information about Jazz and products built on Jazz, like Rational Team Concert Express. The Jazz space includes content from a wide variety of sources, including links, feeds, and comments from experts. FREE! Go There Now!
|
|
|
|
The IBM DB2 Deep Compression ROI tool is designed for DBA’s and IT management personnel to perform a clinical analysis of the cost savings gained from the Storage Optimization feature of DB2 9 for Linux, UNIX and Windows. The feature, also known as Deep Compression, compresses data that lies within a database by up to 80% at times. FREE! Go There Now!
|
|
|
|
You'll get answers to many questions and more from David Barnes, Lead Evangelist for IBM Emerging Internet Technologies. David will discuss aspects of Web 2.0 that bring value to corporations, academia, and government. He'll also discuss IBM's vision around Web 2.0, including the importance of remixability and consumability. The discussion will culminate with examples of various IBM Software Group solutions you can use to get ahead of the Web 2.0 adoption curve. FREE! Go There Now!
|
|
|
|
As businesses grow increasingly dependent upon Web applications to provide services to customers, employees and partners, these complex applications become more difficult to secure. Although traditional security solutions protect Internet infrastructure layers, they do not guard against HTTP and HTML attacks. Many organizations that conduct security testing still deploy applications that allow attackers to manipulate their logic and wreak havoc on their business. To mitigate this risk, development and delivery teams must address Web application security throughout the lifecycle, addressing the many layers detailed in this paper. FREE! Go There Now!
|
|
|
|
Join us for this on demand webcast to learn about developing complex systems more quickly and efficiently. We'll cover market drivers for developing, governing and reusing systems software assets and how you can develop system software assets with Rational Asset Manager. FREE! Go There Now!
|
|
|
|
This tutorial shows new users of IBM WebSphere Business Monitor Version 6.0.2 how to perform the "Hello World" equivalent for monitoring business process applications. It is intended to help you get familiar with the capabilities of the product. FREE! Go There Now!
|
|
|
|
Secure your Web applications with IBM Rational AppScan Standard Edition V7.7, previously known as Watchfire AppScan. This Web application security testing tool automates vulnerability assessments and scans and tests for common Web application vulnerabilities. Visit IBM developerWorks to download a free trial of IBM Rational AppScan Standard Edition V7.7. FREE! Go There Now!
|
|
|
|
Learn how Rational Build Forge can extend a simple compile and package build process by adding customization and deployment capability. Go from a manual method to automating: checking for code changes; getting the latest source; compiling and packaging; customizing; copying to and restarting a deployment server; and sending e-mail notification that a new version is available. FREE! Go There Now!
|
|
|
|
Get a free trial download of the latest version of IBM Rational Tester for SOA Quality V7.0.1, a functional and regression testing tool that enables the creation, comprehension, modification and execution of testing GUI-less Web services. FREE! Go There Now!
|
|
|
|
In this webcast, you'll get an introduction to the eXtreme Transaction Processing (XTP) features of WebSphere Extended Deployment and the common architectural traits required by XTP applications. See how WebSphere Extended Deployment's ObjectGrid feature provides a state-of-the-art infrastructure for hosting XTP applications. FREE! Go There Now!
|
|
|
|
All FREE IBM® developerWorks Tools! |