Using JavaScript to populate a ComboBox with unique values

In this post we’ll answer a question that comes up frequently in the ArcGIS API for JavaScript section of the ESRI Discussion Forum, “How do I populate a ComboBox with unique values”?

Dynamically populated ComboBox dijit

Create a ComboBox

First let’s look at how to build a ComboBox, in this example, we’ll use the Dojo ComboBox dijit (read more details on why at the end of this post). The option tags define the items in our list. In the example below we hardcoded four zoning types (Residential, Commercial, Office and Special).

<select id="mySelect" dojoType="dijit.form.ComboBox">
    <option>RESIDENTIAL</option>
    <option>COMMERCIAL</option>
    <option>OFFICE</option>
    <option>SPECIAL</option>
  </select>

If you have a small, static set of options manually building the list like this is fine; however in cases where you have a large and potentially changing set of choices, it’s a better idea to dynamically populate the list using JavaScript.

Let’s back up and start with an empty ComboBox that we’ll populate programmatically.

<select id="mySelect" dojoType=”dijit.form.ComboBox”>
</select>

Set up the Query Task

We want the ComboBox to be populated when the page loads so let’s use dojo.addOnLoad to register an init function that will be executed on page load. In the init function we’ll use a Query Task to return the records that meet the following query criteria.

  • Specify false for the query’s returnGeometry since we’re just retrieving field values in this query; we don’t need to display any features on the map
  • Set the query’s outFields to the name of the column in your dataset that contains the values you want to display in the ComboBox
  • Optionally define a where clause that restricts the query to a subset of the features in the service

In the example below we define the query to return all non null values for the ZONING_TYPE field.

function init() {
       queryTask = new esri.tasks.QueryTask
                ("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Louisville/LOJIC_LandRecords_Louisville/MapServer/2");

       query = new esri.tasks.Query();
       query.returnGeometry = false;
       query.outFields = ["ZONING_TYPE"];
       query.where = "ZONING_TYPE<> ''";
       queryTask.execute(query,populateList);
 }

Manipulate the Results and Populate the ComboBox

Once the query completes, the populateList function is called and we have access to the query results. In our query results we have duplicate values for each ZONING_TYPE so we’ll need to perform the following steps to determine the unique values:

  • Loop through the results and test each record to see if we’ve seen it before
  • If the record is a value we haven’t seen, build a {name:value} string for that type and store it in an array
  • Create a Dojo ItemFileReadStore and populate it with the {name:value} strings for each zoning type . The ItemFileReadStore is a read only data structure we can use as the datasource for widgets like a Dojo DataGrid or ComboBox.
  • Find the ComboBox using dijit.byId and set the store property to the ItemFileReadStore we created
    function populateList(results) {
        //Populate the ComboBox with unique values
        var zone;
        var values = [];
        var testVals={};

        //Add option to display all zoning types to the ComboBox
        values.push({name:"ALL"})

        //Loop through the QueryTask results and populate an array
        //with the unique values
        var features = results.features;
        dojo.forEach (features, function(feature) {
          zone = feature.attributes.ZONING_TYPE;
          if (!testVals[zone]) {
            testVals[zone] = true;
            values.push({name:zone});
          }
        });
        //Create a ItemFileReadStore and use it for the
        //ComboBox's data source
        var dataItems = {
               identifier: 'name',
               label: 'name',
               items: values
        };
        var store = new dojo.data.ItemFileReadStore({data:dataItems});
        dijit.byId("mySelect").store = store;
    }
    dojo.addOnLoad(init);

Click here to see an example that populates a ComboBox with unique values from a map service.

Notes:

  • Those of you who have worked with Query Tasks frequently may notice a potential pitfall with this approach. Query Tasks are set up to return a maximum of 500 records by default. The server administrator can increase this value, but this typically isn’t recommended. If your query definition will retrieve more than 500 records, there is a chance that the results you receive will not contain all the possible unique values and you may want to explore other options for getting a complete list of unique values.
  • So why didn’t we just use a regular HTML select element? Our sample would have required us to set the innerHTML of the select element, and you’ll run into a bug if you try to do this with Internet Explorer. There are workarounds for the bug but they require different approaches for different browsers. The Dojo ComboBox is more versatile.

Kelly Hutchins of the ArcGIS JavaScript API development team contributed this post.

This entry was posted in Services and tagged , , , . Bookmark the permalink.

Leave a Reply

8 Comments

  1. Kelly says:

    @kg – You are absolutely right, this type of task is well suited for doing the work on the server side if your data is in a database. Great topic for a future blog post outlining how to do this using a database approach
    @Olivier – The following discussion forum post shows how to accomplish this in Flex by building a web service that executes a stored procedure and returns the unique values.
    http://forums.esri.com/Thread.asp?c=158&f=2421&t=278493&mc=8#msgid861465

  2. BillWinston says:

    I am trying to implement this functionality with my own services. I am using an aerial photo tiled layer and a dynamic layer containing my building footprints. I want to populate the drop down list with my building names and then have the user select a name and I’ll make the map zoom to the building and pop-up an info box. My first task is the query but am not able to generate a list from my dynamic service. The service is located at the URL posted above and I can access from a different system where I am working on the script file.

    Is this the place to post the following questio?
    Is there an existing example that includes all of my desired features?
    What could be causing my query feature to fail to load into the combobox?

  3. Kelly says:

    @Bill – The first thing to check is to see if the query is returning any features. I try to test my queries using the ArcGIS Services directory first to make sure the syntax is correct.
    http:///ArcGIS/rest/services
    If it is returning the correct results are you getting any other errors?

    You can use map.setExtent to zoom, here’s a snippet that shows how to use from the discussion forum.

    There are several samples in the help that show how to display InfoWindows, here’s a link to one that display the window when a user clicks on the map:http://resources.esri.com/help/9.3/arcgisserver/apis/javascript/arcgis/help/jssamples_start.htm#jssamples/map_infowindow.html
    Here’s one that shows how to display the window immediately after a query:
    http://resources.esri.com/help/9.3/arcgisserver/apis/javascript/arcgis/help/jssamples_start.htm#jssamples/query_showinfowindow.html

  4. Kelly says:

    @Kelly

    If you have spaces in your field names you can use syntax like the following:
    zone=feature.attributes["IRIS.IRIS_ADMIN.ESRI_INSTRUCTORS.Instructor_Name"];

  5. suhana says:

    Is this working in arcgis api version 3.0? I tried but it doesn’t populate the drop down. store is not identified as a valid attribute?
    but if the combo box is declared programmatically, rather than in the markup, it works. but I prefer to declare it in the markup with the dojoType and then populate it using the javascript like you have done. Any suggestions?

    • jwarzi says:

      I would also be interested in suggestions on how best to make this work using 3.x js api

      • jwarzi says:

        Update, it was the line dijit.byId(“mySelect”).store = store; in the code that was causing this sample to not work, once I updated it to dijit.byId(“mySelect”).set(“store”, store); the this sample started working using the 3.x api