Skip to page content or Skip to Accesskey List.

Work

Main Page Content

Dynamically Filtering Dropdown Lists In Javascript

Rated 4.04 (Ratings: 8)

Want more?

  • More articles in Code
 
Picture of stormy

Justin Whitford

Member info

User since: 04 Sep 2001

Articles written: 2

This article describes a technique that takes input from a form text field and uses it to bring matching options to the top in a dropdown list

Have you ever hit a dropdown box that was just too long?

There were so many items that finding the one you wanted was a hassle.

You hit the first letter of the option you were looking for, only to find that there are at least 50 options starting with that letter

- or worse, the list wasn't sorted alphabetically and you had to type the letter 20 times to get to your option.

Maybe the option you wanted was phrased differently than you expected. It didn't even start with the letter you were typing!

Sound familliar? Well, there are a couple of solutions.

One way around this problem is to stage your dropdown boxes;

what you choose in box 1 determines your options in box 2, etc.

Joe's article,

Creating Dynamic Select Boxes

, describes how this can be done using ColdFusion, JavaScript and WDDX. (if there is sufficient interest, I'll throw together an article that presents a Javascript-only method)

This is often a great way to reduce cumbersome lists into managable chunks.

However this technique is based on the assumption that your visitors understand the way you've categorised the options.

Take for example a simple dropdown list of countries. In the past, I've found my beloved Australia under categories such as "Asia", "Pacific", "South Pacific", and, "Oceania". Searching for options this way can be a bit hit and miss.

Another solution to the "long list" problem is to allow your visitor to make their option magically rise to the top of the list...

Search:

The Code

For those who are in a hurry (or who are already sick of reading), here is the code with ample comments:

<html>

<head>

<title>Dropdown Filter</title>

</head>

<body>

<script language="JavaScript" type="text/javascript">

<!--

/*

- Give Credit Where Its Due -

Please acknowledge this article and its author, at

least in code comments, when using this code.

Author: Justin Whitford

Source: www.evolt.org

Thank you.

*/

/*

filtery(pattern, list)

pattern: a string of zero or more characters by which to filter the list

list: reference to a form object of type, select

Example:

<form name="yourForm">

<input type="text" name="yourTextField" onchange="filtery(this.value,this.form.yourSelect)">

<select name="yourSelect">

<option></option>

<option value="Australia">Australia</option>

.......

*/

function filtery(pattern, list){

/*

if the dropdown list passed in hasn't

already been backed up, we'll do that now

*/

if (!list.bak){

/*

We're going to attach an array to the select object

where we'll keep a backup of the original dropdown list

*/

list.bak = new Array();

for (n=0;n<list.length;n++){

list.bak[list.bak.length] = new Array(list[n].value, list[n].text);

}

}

/*

We're going to iterate through the backed up dropdown

list. If an item matches, it is added to the list of

matches. If not, then it is added to the list of non matches.

*/

match = new Array();

nomatch = new Array();

for (n=0;n<list.bak.length;n++){

if(list.bak[n][1].toLowerCase().indexOf(pattern.toLowerCase())!=-1){

match[match.length] = new Array(list.bak[n][0], list.bak[n][1]);

}else{

nomatch[nomatch.length] = new Array(list.bak[n][0], list.bak[n][1]);

}

}

/*

Now we completely rewrite the dropdown list.

First we write in the matches, then we write

in the non matches

*/

for (n=0;n<match.length;n++){

list[n].value = match[n][0];

list[n].text = match[n][1];

}

for (n=0;n<nomatch.length;n++){

list[n+match.length].value = nomatch[n][0];

list[n+match.length].text = nomatch[n][1];

}

/*

Finally, we make the 1st item selected - this

makes sure that the matching options are

immediately apparent

*/

list.selectedIndex=0;

}

// -->

</script>

<form name="yourForm">

Search <input type="text" name="yourTextField" onkeyup="filtery(this.value,this.form.yourSelect)" onchange="filtery(this.value,this.form.yourSelect)">

<select name="yourSelect">

<option></option>

<option value="Australia">Australia</option>

<option value="China">China</option>

<option value="England">England</option>

<option value="New Zealand">New Zealand</option>

</select>

</form>

</body>

</html>

Discussion

How it Works

If the visitor does several searches, the dropdown list could get rather ugly from the constant shuffling. To combat this, we make

a copy of the dropdown list and use that as the master copy. We don't want to do this every time the list is filtered - just the

first time.

The first thing the function does is check whether a master copy exists. If one does not, then it attaches and populates a master copy array to the form's select object

The function then creates two arrays: one for matches and one for non-matches. Now, as it iterates through the master copy, it appends items to either of the two arrays.

Once each item in the dropdown has been assessed, the matches and non-matches arrays are written back to the select object.

Finally, the function forces the first item in the list to be selected - this makes sure that the matching options are immediately apparent to the visitor

Allowing Advanced Search

If you're not fussed about supporting version three browsers, you can enhance the function by having it match by regular expression.

Simply add this near the top of the function:

pattern = new RegExp(pattern,"i");

... and replace...

if(list.bak[n][1].toLowerCase().indexOf(pattern.toLowerCase())!=-1){

... with...

if(pattern.test(list.bak[n][1])){

Your visitors will now be able to type:

  • "^au" to get all items starting with au.
  • "ia$" to get all items ending with ia.
  • "9\d\d" to get all items containing numbers between 900 and 999.
  • etc, etc.

For more information on regular expressions, see the developer.netscape site. There are also several articles on evolt regarding regular expressions.

Cross Browser Compatability

The following table lists the browsers and platforms on which I have tested this code.

Browser Compatability Table
Browser / VerWin NTWin 98Linux (SuSE 8)
Internet Explorer 5.5 Y--
Internet Explorer 6.0 -Y-
Netscape 3.x Y--
Netscape 4.7x YY-
Netscape 6.x *-*
Mozilla 0.9.8 --*
Mozilla 1.2.1 -Y-
Phoenix 0.5 -Y-
Opera 6.01 --Y

Y : Tested and OK

N : Tested and not OK

- : Not tested

*There seems to be a bug in Mozilla 0.9.8 and therefor, not surprisingly, Netscape 6.x. Making changes to the dropdown list in these browsers results in an inordinate amout of CPU usage. It works, but the browser may hang for a noticable amount of time, depending on the size of the list and the CPU speed of the PC. Mozilla 1.2.1 is fine, so I assume that Netscape 7 is also fine.

A self proclaimed web monkey, Justin is a 'Jack of all trades' when it comes to web design & coding. Justin's hobby became a career when he was offered a junior web design position whilst chatting in an IRC channel. Having recently dropped out of a teaching degree , he eagerly accepted the job.

Justin's natural curiosity and his hunger for knowledge have seen him play/work with such technologies as HTML, XML, VRML, CSS, JavaScript, Flash, Perl, ASP, Java, JSP and PHP. Get him interested in a problem and he'll happily set about solving it using whatever tools and technologies are available.

Although preferring coding over design, Justin is comfortable with graphics/multimedia packages as varied as Adobe Photoshop(v5/6), Micrographix Picture Publisher(v5), Macromedia Fireworks(v4/5), and Flash(v4/5). The open source package, "the GiMP", is the latest to capture his attention.

Justin currently lives in Sydney, Australia.

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.org Evolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.