AJAX In Action [168]
strSql = "SELECT TerritoryDescription, " & _
" TerritoryID" & _
" FROM Territories" & _
" WHERE " & strWhere & _
" ORDER BY TerritoryDescription"
Else
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. 9.6 Refactoring
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. Licensed to jonathan zheng 346 CHAPTER 9 Dynamic double combo 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 introduced briefly in chapter 3, and more thoroughly in chapter 5, 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. 9.6.1 New and improved net.ContentLoader Let’s start by thinking about how the constructor should be changed. Consider the following constructor: net.ContentLoader = function( component, url, method, requestParams ) { this.component = component; this.url = url; net.ContentLoader this.requestParams = requestParams; state this.method = method; } 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 Licensed to jonathan zheng Refactoring 347 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