Skip to page content or skip to Accesskey List.
Search evolt.org
evolt.org login: or register

Work

Main Page Content

Dynamically Filtering Dropdown Lists in Javascript

Rated 4.04 (Ratings: 8) (Add your rating)

Log in to add a comment
(19 comments so far)

Want more?

 
Picture of stormy

Justin Whitford

Member info | Full bio

User since: September 04, 2001

Last login: August 15, 2006

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,&quot;i&quot;);

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

very nice....

Submitted by technophobe on February 17, 2003 - 02:40.

add in a doc.write so that users with .js turned off dont get presented with the search box and i'd use it :)

login or register to post comments

Data-Driven

Submitted by kevinmarsh on February 17, 2003 - 14:09.

What about when the dataset is so large that downloading the whole list is impossible. How would I select, say, a letter and then have another dropdown fill with data from MySQL with those items that start with that letter?

login or register to post comments

Dynamic population should be possible

Submitted by brothercake on February 17, 2003 - 15:05.

One way would be to keep each chunk of list items in a .js file, and dynamically change the src. Say the script element has the id "scr", in response to key-entries you could call a function something like this:

function changeScript(whichLetter){

	var scrObj = document.getElementById("scr");
	if(typeof scrObj!="undefined") { document.body.removeChild(scrObj); }

	scrObj = document.createElement("script");
	scrObj.id="scr";
	scrObj.type="text/javascript";
	scrObj.src=whichLetter+".js";

	document.body.appendChild(scrObj);

	}

And then re-populate the selector in the DOM, or using innerHTML. This would work in ie6 and mozilla, but not opera 7.

To save having multiple files, you should be able to keep all the data in one server-generated .js file, and then pass a query string through the src, which you can process with REQUEST URI ... I think (haven't actually tried it, but the theory sounds good).

login or register to post comments

An enhanced version?

Submitted by deto on March 31, 2003 - 15:44.

In the past I was thinking about something similar... Look at this prototype I have finished yesterday :) http://biografica.tzone.it/examples/filterlist.html Who is interested in adding javascript for filtering and toggle list visibility? it needs also some css work...

login or register to post comments

Why all the array juggling and filtering?

Submitted by codepo8 on April 1, 2003 - 06:10.

All you really want is to start selecting from the element that matches your pattern, especially in a language list.

So this

function filtery(pattern,list){
	pattern = new RegExp(''''^''''+pattern,"i"); 
	i=0;
	sel=0;
	while(i

is actually enough, or? Check it live

login or register to post comments

Mmm..doesn't work

Submitted by pixelmech on April 7, 2003 - 06:02.

This doesn't work for me in IE5.5 Win2k. For example, when I put in 'g' I get 'Afghanistan'.

login or register to post comments

I'm working on a free form field...and I need hel

Submitted by deto on April 7, 2003 - 15:40.

Look at my experiments at http://biografica.tzone.it/examples/filterlist.html. It's well commented. I hope you'll want to help me with your Css and Javascript knowledges :) Thank you.

login or register to post comments

RE: Mmm..doesn't work

Submitted by stormy on April 7, 2003 - 17:08.

That would be because Afghanistan is the 1st item containing a G. The list is staying in alphabetical order, but bringing all items that contain G to the top.

login or register to post comments

RE: Why all the array juggling and filtering?

Submitted by stormy on April 7, 2003 - 18:42.

You'd use the different techniques for different effects. The example that you (codepo8) have linked to grabs the first match and selects it. The example presented here grabs all matches and brings them to the top. The different techniques have advantages and drawbacks depending upon where they're used. If your list is not sorted alphabetically, then the technique here is probably more helpful. If your list is sorted and your search is exclusively for a beginning letter combination, then your example is a better option. If your search is for a letter combination anywhere in an item, then this code is probably the way to go.

login or register to post comments

True

Submitted by codepo8 on April 8, 2003 - 03:17.

You are right there. Then again, from a usability point of view, a list long enough to need filtering should be alphabetical. And sorry for wrecking your article with that badly formed code example :-/

login or register to post comments

Can this work for DataGrid?

Submitted by btang on July 3, 2003 - 10:48.

Is there any one know. How can we Dynamically Filtering dataGrid with Javascript and Asp. I mean that we can dynamically match the content in DataGrid when we type somthing in textbox?

login or register to post comments

Dynamic dropdown list

Submitted by LewisPJ on July 25, 2003 - 18:44.

I have seen some sites that have a text field for input into which the user can type any string. If the typed characters match, an object appears (looking like a textarea with a triangular stretch button in the lower right corner) with a list starting with the first item whose respective characters match the typed string. I acts like the Address field in a browser. Has anyone seen how to code this object? Thanks

login or register to post comments

RE: LewisPJ - Dynamic dropdown list

Submitted by stormy on July 27, 2003 - 15:57.

Sounds like the browser-based feature whereby the browser remembers what you've previously typed into a form field.

You could probably rig something up to look like this by:
  • having an array of options;
  • applying the concepts from this example and codepo8's variation; and
  • using a layer to present the matching options

login or register to post comments

Great job

Submitted by ashcoder on May 17, 2004 - 12:15.

This feature is awesome. I have been looking for something like this drop down list for a while. Thank you for putting your efforts into this!

login or register to post comments

amazing - fabulous solution

Submitted by smn on November 30, 2004 - 10:53.

I love what you have got here... I would like to apply this for myself, but the only issue I have is that my phrases are in database and I'd like to pull them dynamically rather then Hard-Coding them as you have done with countries. I want to use this for Street Names in my town. your input/directions will be appreciated... can it be done?

login or register to post comments

DB doesn't matter

Submitted by pixelmech on November 30, 2004 - 10:56.

It doesn't matter where the data comes from, whether it is static or fed to the page from the DB. You build your select based on your DB data and apply the script.

login or register to post comments

DB doesn't matter

Submitted by smn on November 30, 2004 - 11:45.

pixelmech: do you have an example where I can apply... My Table Name is LKP_STREET and the column that consists of all the streets is called STREET. The Database would be ORACLE or ACCESS. thanks smn

login or register to post comments

Browser Compatibility

Submitted by biggy97 on February 5, 2006 - 16:06.

I found the article informative and interresting. However in trying to protoype the code for my website, flirten, i found had a problem getting it to work under Maxthon.

login or register to post comments

only check from the left

Submitted by mbetel on February 6, 2006 - 18:52.

If you want to check if the search pattern matches the beginning of the selectbox string you can change the line in filtery from: if(list.bak[n][1].toLowerCase().indexOf(pattern.toLowerCase())!=-1){ to: if(list.bak[n][1].substring(0,pattern.length).toLowerCase().indexOf(pattern.toLowerCase())!=-1){ Love the function and have implemented it immediately on my sites.. its better the the builtin Firefox multicharacter select box functionality since it sorts all matched patterns to the top! Michiel

login or register to post comments

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

evolt.orgEvolt.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.