AJAX In Action [169]
net.ContentLoader.prototype = {
method1: function(a, b, c) {
First method attached
},
to prototype
method2: function() {
Second method
},
method3: function(a) {
}
};
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 Licensed to jonathan zheng 348 CHAPTER 9 Dynamic double combo 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 9.6, and we’ll never have to write it again. Listing 9.6 The getTransport method getTransport: function() { var transport; if ( window.XMLHttpRequest ) Native transport = new XMLHttpRequest(); object else if ( window.ActiveXObject ) { try { transport = new ActiveXObject('Msxml2.XMLHTTP'); IE ActiveX } object catch(err) { transport = new ActiveXObject('Microsoft.XMLHTTP'); } } return transport; }, 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. 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 runtime 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: var a,b,c; Assume initialized with runtime values var ajaxHelper = new net.ContentLoader(...); ajaxHelper.sendRequest( "param1=" + a, "param2=" + b, "param3=" + c ); So given this usage requirement, sendRequest is defined as shown in listing 9.7. Licensed to jonathan zheng Refactoring 349 Listing 9.7 The sendRequest method sendRequest: function() { var requestParams = []; b Store for ( var i = 0 ; i < arguments.length ; i++ ) { arguments requestParams.push(arguments[i]); in an array } var request = this.getTransport(); c Create the request.open( this.method, this.url, true ); request request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded'); var oThis = this; Specify the d request.onreadystatechange = function() { callback oThis.handleAjaxResponse(request) }; request.send( this.queryString(requestParams) ); e Send the request }, This method splits the process of sending a request into four steps. Let’s look at each step of the process in detail: b This step takes advantage of the fact that JavaScript creates