October 28, 2016
Hot Topics:

Advanced Features in Creating a Double-Combo Linked List with Ajax

  • January 17, 2006
  • By Dave Crane, Eric Pascarello, and Darren James
  • Send Email »
  • More Articles »

Advanced issues

In the previous article, Creating a Double-Combo Linked List with Ajax, we built a simplified version of a double-combo script. We send a single parameter to the server, and we return a set of results for the single selected item. You may find that you need to change the way that this application works. You may want to add another element to the form so that you have a triple combo. You may even want to allow the user to select multiple items in the first list. If this is the case, then the following sections will give you ideas on how to implement them.

Allowing multiple-select queries

The code we have discussed so far is a simple example, allowing a user to select only one option from each selection list. In some cases, a user may be required to select more than one option from the first list. That means the second list in our combination will be populated with values corresponding to each selected option in the first list. With some simple changes to our client-side and server-side code, we can make this happen.

The first thing to do is to set up the first selection list to allow multiple items to be chosen. To do this, we need to add the multiple attribute to the select tag. To specify how many options to display, we can add the size attribute. If size is smaller than the number of options, the selection list will be scrollable to reveal those that are not visible.

<select name="ddlRegion" multiple size="4"
   <option value="1">Eastern</option>
   <option value="2">Western</option>
   <option value="3">Northern</option>
   <option value="4">Southern</option>

The next step is to change the FillTerritory() function. Instead of just referencing the selected index of the select element, we need to loop through all the options and find each of the selected values. We add the value of each selected option to the parameter string:

function FillTerritory(oElem,oTarget){
   var url = 'DoubleComboMultiple.aspx';
   var strParams = "f=" + oTarget.form.name +
      "&e=" + oTarget.name;
   for(var i=0;i<oElem.options.length;i++){
         strParams += "&q=" + oElem.options[i].value;

   var loader1 = new

The last thing to do is change the code of the server-side script to handle the multiple values passed in the request. In .NET, the multiple values are represented in a single string, separated by commas. In order to get each item individually, we need to split the string into an array. We can then build our WHERE clause for the SQL statement by looping through the array.

Dim strQuery As String = Request.Form("q")
Dim strWhere As String = ""
Dim arrayStr() As String = strQuery.Split(",")
Dim i As Integer
For Each i In arrayStr
   If strWhere.Length > 0 Then
      strWhere = strWhere & " OR "
   End If
   strWhere = strWhere & " regionid = " & i

Dim strSql As String = "SELECT " & _
           " TerritoryDescription, " & _
           " TerritoryID" & _
           " FROM Territories" & _
           " WHERE " & strWhere & _
           " ORDER BY TerritoryDescription"

With these changes, a user to can select multiple regions from the first selection list, and the territories corresponding with every selected region will appear in the second list.

Moving from a double combo to a triple combo

Moving to a double combo to a triple combo requires only a small number of changes, depending on how we want to handle the logic on the server. The first option is to move our logic into multiple server-side pages so that we can run a different query in each. That would mean adding another parameter to each selection list's onchange handler, representing the URL of the server-side script to call.

The other option can be as simple as adding an if-else or a switch-case statement to the server-side code. The if-else structure needs a way to determine which query to execute in order to return the appropriate values. The simplest check is to decide which SQL query to use based on the name of the select element to be populated. So, when we are performing a triple combo, we can check that the value of the strElem variable. This way, we do not need to make any changes to the onchange event handlers in the client-side code.

Dim strSql As String
If strElem = "ddlTerritory" Then
    strSql = "SELECT TerritoryDescription, " & _
             " TerritoryID" & _
             " FROM Territories" & _
             " WHERE " & strWhere & _
             " ORDER BY TerritoryDescription"
    strSql = "SELECT Column1, Column2" & _
             " FROM TableName" & _
             " WHERE " & strWhere & _
             " ORDER BY Column2"
End If

With this solution, as long as the drop-down lists have unique names, you will be able to have multiple combination elements on the page without having to separate all of the logic into different server-side pages.


So what do you think is lacking at this point? I suspect I know what you're thinking—generality. This is an extremely cool, jazzed-up technique for implementing double combos, but it needs a little polish to be a generalized component. We'll get there, so hang tight. But first, let's address something even more fundamental: encapsulation of some of the Ajax plumbing itself. The net.ContentLoader is a good start. Let's build on this object to make our handling of AJAX even more seamless. Ideally we should be able to think of this entity as an Ajax "helper" object that does all the heavy lifting associated with Ajax processing. This will allow our component to focus on double combo–specific behaviors and reduce the amount of code required by the rest of our components as well. Our improved net.ContentLoader object should ideally encapsulate the state and behavior required to perform the following tasks:

  • Creation of the XMLHttpRequest object in a cross-browser fashion, and as an independent behavior from sending requests. This will allow callers to use the creation method independently from the rest of the object. This is useful if the caller is using another idiom, framework, or mechanism for request/response activities.
  • Provide a more convenient API for dealing with request parameters. Ideally the caller should just be able to pass state from the application and let the net.ContentLoader "helper" worry about creating querystrings.
  • Routing the response back to a component that knows how to handle it and performing appropriate error handling.

So let's start our refactoring of net.ContentLoader, and then we'll move on to repackaging our double combo as a component.

New and improved net.ContentLoader

Let's start by thinking about how the constructor should be changed. Consider the following constructor:

Click here for a larger image.

The constructor shown here is called with four arguments. The first, component, designates the object that is using the services of this helper. The helper object will assume that component has an ajaxUpdate() method to handle responses and a handleError() method to handle error conditions. More about that later. Second, as before, url designates the URL that is invoked by this helper to asynchronously get data from the server. The method parameter designates the HTTP request method. Valid values are GET and POST. Finally, the requestParameters argument is an array of strings of the form key=value, which designate the request parameters to pass to the request. This allows the caller to specify a set of request parameters that do not change between requests. These will be appended to any additional request parameters passed into the sendRequest method discussed below. So our helper can now be constructed by a client as follows:

var str = "Eastern";
var aComp = new SomeCoolComponent(...);
var ajaxHelper = new net.ContentLoader( aComp,
                "getRefreshData.aspx", "POST",
                [ "query=" + str, "ignore_case=true" ] );

Now let's consider the rest of the API. One thing I should mention at this point is the stylistic nature of the code sample. The methods of this object are scoped to the prototype object attached to the constructor function. This is a common technique when writing object-oriented JavaScript, as it applies the method definitions to all instances of the object. However, there are several ways of syntactically specifying this. One of my favorites (a pattern I picked up from the prototype.js library packaged within Ruby On Rails) is to create the prototype object literally, as shown here:

The thing we like about this syntactically is that it is expressed minimally. The way to read this is that the outermost open and close curly braces represent an object literal, and the content is a comma-delimited list of property-value pairs within the object. In this case our properties are methods. The property-value pairs are specified as the name of the property, followed by a colon, followed by the value of the property. In this case the values (or definitions if you prefer) are function literals. Piece of cake, huh? Just bear in mind that the methods shown from here on out are assumed to be contained within the prototype object literal as shown here. Also, note that the last property doesn't need—indeed can't have—a comma after it. Now let's go back to the task at hand: refactoring the API.

The API should address the requirements that we mentioned above, so let's take each one in turn. The first thing we need is an independent behavior to handle the creation of the XMLHttpRequest object in a cross-browser fashion. That sounds like a method. Fortunately, we've implemented this one a few times already. All we need to do is create it as a method of our helper, as shown in listing 6, and we'll never have to write it again.

Listing 6: The getTransport method

Click here for a larger image.

There's not much explanation required here, since we've covered this ground many times, but now we have a cleanly packaged method to provide a cross-browser Ajax data transport object for handling our asynchronous communications.

Page 1 of 3

Comment and Contribute


(Maximum characters: 1200). You have characters left.



Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date
Rocket Fuel