October 24, 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 »

The second requirement we mentioned was to provide a more convenient API for dealing with request parameters. In order for it to be used across a wide variety of applications, it is almost certain that the request being sent will need run-time values as parameters. We've already stored some initial state that represents request parameters that are constant across requests, but we'll also need runtime values. Let's decide on supporting a usage such as the following code:

So given this usage requirement, sendRequest is defined as shown in listing 7.

Listing 7: The sendRequest method

Click here for a larger image.

This method splits the process of sending a request into four steps. Let's look at each step of the process in detail:

The following list references the callouts in listing 7.

  1. This step takes advantage of the fact that JavaScript creates a pseudo-array named arguments that is scoped to the function. As the name suggests, arguments holds the arguments that were passed to the function. In this case the arguments are expected to be strings of the form key=value. We just copy them into a first-class array for now. Also, note that all variables created in this method are preceded by the keyword var. Although JavaScript is perfectly happy if we leave the var keyword off, it's very important that we don't. Why? Because, if we omit the var keyword, the variable is created at a global scope—visible to all the code in your JavaScript universe! This could cause unexpected interactions with other code (for example, someone names a variable with the same name in a third-party script you have included). In short, it's a debugging nightmare waiting to happen. Do yourself a favor and get accustomed to the discipline of using locally scoped variables whenever possible.
  2. Here our method uses the getTransport method we defined in listing 6 to create an instance of an XMLHttpRequest object. Then the request is opened and its Content-Type header is initialized as in previous examples. The object reference is held in a local variable named request.
  3. This step takes care of the response-handling task. I'll bet you're wondering why the variable oThis was created. You'll note that the following line—an anonymous function that responds to the onreadystatechange of our request object—references oThis. The name for what's going on here is a closure. By virtue of the inner function referencing the local variable, an implicit execution context or scope is created to allow the reference to be maintained after the enclosing function exits. (See appendix B for more on closures.) This lets us implement handling of the Ajax response by calling a first-class method on our ajaxHelper object.
  4. Finally, we send the Ajax request. Note that the array we created in step 1 is passed to a method named queryString that converts it to a single string. That string becomes the body of the Ajax request. The queryString method isn't really part of the public contract we discussed earlier, but it's a helper method that keeps the code clean and readable. Let's take a look at it in listing 8.

Listing 8: The queryString method

Click here for a larger image.

This method takes the request parameters that our net.ContentLoader was constructed with, along with the additional runtime parameters that were passed into the sendRequest method, and places them into a single array. It then iterates over the array and converts it into a querystring. An example of what this achieves is shown here:

var helper = new net.ContentLoader( someObj, someUrl,
                                    "POST", ["a=one", "b=two"] );
var str = ajaxHelper.queryString( ["c=three", "d=four"] );
str => "a=one&b=two&c=three&d=four"

The last thing we need to do to have a fully functional helper object is to collaborate with a component to handle the response that comes back from Ajax. If you've been paying attention, you probably already know what this method will be named. Our sendRequest method already specified how it will handle the response from the onreadystatechange property of the request:

request.onreadystatechange = function(){

That's right, kids; all we need to do is implement a method named handleAjaxResponse. Listing 9 contains the implementation.

Listing 9: The Ajax response handler methods

Click here for a larger image.

All the method does is check for the appropriate readyState of 4 (indicating completion) and notifies the this.component that the response is available. But we're not quite finished yet. The other requirement we said we would address is to handle errors appropriately. But what is appropriate? The point is, we don't know what's appropriate. How to handle the error is a decision that should be deferred to another entity. Therefore we assume that our client, this.component, has a handleError method that takes appropriate action when the Ajax response comes back in a way we didn't expect. The component may in turn delegate the decision to yet another entity, but that's beyond the scope of what we care about as a helper object. We've provided the mechanism; we'll let another entity provide the semantics. As mentioned earlier, we're assuming that this.component has an ajaxUpdate and a handleError method. This is an implicit contract that we've created, since JavaScript isn't a strongly typed language that can enforce such constraints.

Congratulations! You've morphed net.ContentLoader into a flexible helper to do all the Ajax heavy lifting for your Ajax-enabled DHTML components. And if you have a DHTML component that's not yet Ajax-enabled, now it'll be easier! Speaking of which, we have a double-combo component to write.

Creating a double-combo component

We've laid some groundwork with our net.ContentLoader to make our task here much easier, so let's get started. Let's assume that our assignment as a rock-star status developer is to create a double-combo script that can be reused in many contexts across an application, or many applications for that matter. We need to consider several features in order to meet this requirement:

  • Let's assume that we may not be able or want to directly change the HTML markup for the select boxes. This could be the case if we are not responsible for producing the markup. Perhaps the select is generated by a JSP or other server-language-specific tag. Or perhaps a designer is writing the HTML, and we want to keep it as pristine as possible to avoid major reworks caused by a round or two of page redesigns.
  • We want a combo script that is able to use different URLs and request parameters to return the option data. We also want the design to accommodate further customization.
  • We want to be able to apply this double-combo behavior potentially across multiple sets of select tags on the same page, also potentially setting up triple or quadruple combos, as discussed earlier.

Starting from the perspective of our first task, keeping the HTML markup as pristine as possible, let's assume the markup shown in listing 10 is representative of the HTML on which we will be operating.

Listing 10: Double-combo HTML markup listing


<form name="Form1">
   <select id="region" name="region" >
   <select id="territory" name="territory" />

What we need is a DoubleCombo component that we can attach to our document to perform all of the double-combo magic. So let's work backwards and consider what we would want our markup to look like; then we'll figure out how to implement it. Let's change the markup to look something like listing 11.

Listing 11: Double-combo HTML modified markup listing

Click here for a larger image.

The markup has now changed in the following ways:

  • A function has been created that injects all desired component behaviors into our document.
  • An onload handler has been added to the body element that calls this function.

Note that nothing within the body section of the page has been modified. As stated earlier, this is a good thing. We've already satisfied our first requirement. But, looking at our injectComponentBehaviors() function, it's apparent that we have some more work to do. Namely, we need to create a JavaScript object named DoubleCombo that, when constructed, provides all the behaviors we need to support double-combo functionality.

DoubleCombo component logic

Let's start by looking more closely at the semantics of our component creation. Our injectComponentBehaviors() function creates a DoubleCombo object by calling its constructor. The constructor is defined in listing 12.

Listing 12: DoubleCombo constructor

Click here for a larger image.

This should be a familiar construct at this point; our constructor function initializes the state of our DoubleCombo. A description of the arguments that should be passed to the constructor is shown in table 2.

Table 2: Description of arguments

Argument Description
masterId The ID of the element in the markup corresponding to the master select element. The selection made in this element determines the values displayed by a second select element.
slaveId The ID of the element in the markup corresponding to the slave select element. This is the element whose values will be changed when the user makes a choice from the master select.
options A generic object that provides other data required by the double combo.

Consider the nature of the state maintained by the DoubleCombo object—particularly the URL and options. These two pieces of state satisfy the second functional requirement mentioned earlier. That is, our component can accommodate any URL for data retrieval and is customizable via the options parameter. Currently the only thing we assume we'll find within the options object is a requestParameters property. But, because the options parameter is just a general object, we could set any property on it needed to facilitate further customizations down the road. The most obvious kinds of properties we could place in our options object are such things as CSS class stylings and the like. However, the style and function of the double combo are fairly independent concepts, so we'll leave the styling to the page designer.

Page 2 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