How to Create an Ajax Autocomplete Text Field: Part 5/Page 2 | WebReference

How to Create an Ajax Autocomplete Text Field: Part 5/Page 2

[previous] [next]

How to Create an Ajax Autocomplete Text Field: Part 5 [con't]

Variable Declarations

Here are the variables that we'll need to declare at the top of the script:

The isIE variable is set to a boolean type according to whether or not the browser recognizes ActiveX objects. A value of true would tell us that the browser is Internet Explorer since ActiveX is a proprietary Microsoft product. The completeTable variable will store the dynamic table that contains the autocomplete list selections. The completeField will hold a reference to the textbox.

The init() Function

The init() function is called from the document onload event. This is where we set the global variables to their respective fields and define some default properties. We can call the DOM getElementById() function to obtain a reference to the page elements. It uses the element's ID attribute to return a reference to it. In the event that the same ID attribute exists for multiple elements, only the first element is returned. A null is returned if no matching element is found. The autorow refers to the table row below the Autocomplete text field (the completeField) and is used to determine the position of the list on the screen. This is done via the findPos() function, which returns a coordinates object containing the top and left element properties. The menu variable holds a reference to the <DIV> element containing the Autocomplete list table (the completeTable). Setting its top property to the top of the table autorow positions the <DIV> directly beneath the Autocomplete text field. Similarly, setting the left property to the Autocomplete text field's left property will align it vertically with the textbox. The completeField textbox could have been used to determine the top position as well but that would also require the additional step of adding its height. The completeTable's visibility property is set to "hidden" in order to hide the table until a character is entered in the text field:

The findPos() Function

The findPos() function uses two alternate means of determining an element's position on the Web page:

The first approach uses the more common W3C DOM offsetLeft and offsetTop properties. These give the position of the element relative to an arbitrary ancestor node, known as the offsetParent. I say arbitrary because unfortunately, different browsers and even different versions of the same browser give a different offsetParent. As a case in point, as of Microsoft Internet Explorer 5, the offsetParent property returns the <TABLE> object for the <TD> tag, whereas in Internet Explorer 4.0 it returned the <TR> object. This can get a bit complicated. The solution is the while loop that iterates through the the offsetParents. Here's how it works: the offsetParent will also have the offsetTop and offsetLeft properties, giving its position relative to its offsetParent, and so the cycle continues, until the offsetParent is the topmost node in the document, which will always be at offset (0,0).

The second uses the simple, but practically obsolete Netscape-compatible x and y properties.

Both the left and top are returned as an Object literal. This allows us to retrieve the properties using the Left and Top member property accessors:

The autoComplete() Function

Every time a character is entered in the Autocomplete field, the autoComplete() function makes a call to the server to update the list. The first part of the if statement weeds out strings that don't require a server call. To keep our example simple, the code checks for a blank string rather than parse it for valid characters. One of the effects of this code is that the clearTable() function is called whenever the field is cleared using the "Backspace" button. If there's a search string in the field, the script passes its value to the AutocompleteServlet in the url query string, creates a new AJAX object and sends the search string using a GET call. Formulating the URL string may present a bit of a hurdle for those unfamiliar with AJAX and Servlets so let's go over what's required to construct it.

In general, an URL has this form: protocol//host:port/pathname#hash?search. We're using a relative link, so we really only need to provide the name of the page , rather than the full path. Servlets are different from most Web pages in that its properties are configured in the deployment descriptor web.xml file. One of the properties that's in the web.xml file is the name of the servlet class. Hence, you are essentially calling the servlet by its alias and not by the proper servlet name ("autocomplete," in our case). The search portion of the URL is made up of name/value pairs, separated by ampersands (&). On the server, these parameters are passed on to the servlet. We're sending two name/value pairs: the action and the searchString. The action is the request property that tells the servlet what we'd like it to do, much like ordering a meal from a menu. A value of "complete" is a request to provide a list of matching items that will be used to populate the Autocomplete list. The searchString is the partial symbol or fund name that we want to complete. Unlike the action parameter, which never changes, the searchString is updated after every character.

The result of the initRequest() function — an AJAX object — is stored in the req variable. The XMLHttpRequest object's onreadystate property must have a function assigned to it in order to process results of the AJAX call, once it returns from the server. There are four readyStates, but the last one (#4) is by far the most used, since it's the only one where all the results have been returned. Here's the list of readyState values and their meaning:

  1. The request is uninitialized (before you've called open()).
  2. The request is set up, but not sent (before you've called send()).
  3. The request was sent and is in process (you can usually get content headers from the response at this point).
  4. The request is in process; often some partial data is available from the response, but the server isn't finished with its response.
  5. The response is complete; you can get the server's response and use it.

The status property is the HTTP status header. There are many possible values, but only two interest us: 200 - OK and 204 - No content. A status of 200 is the green light to go ahead and call the parseMessages() function. A status of 204 means that nothing was returned in response to our request, so we clear the list table, in case there was something in it previously.

Now that we've set the callback function to handle the AJAX object's response, we can proceed to send the request to the server. The open() function establishes the connection to the server and send() makes the actual call. The send() function's parameter is only used for uploads, so we can set it to null. For more information on AJAX calls, see my URPMs: AJAX Edition article.

The initRequest() Function

The initRequest() function is a basic "boilerplate" implementation of an AJAX Request object initialization. Internet Explorer uses ActiveX objects for AJAX calls. In all other browsers, we have to create a new XMLHttpRequest object:

The parseMessages() Function

The parseMessages() function is responsible for processing the AJAX response and populating the list. To be sure that we're starting with and empty list every time, we call clearTable(). The first if statement checks to see if anything was returned from the server. While the previous check for a return status of 204 should eliminate empty responses, it's possible to have an empty string returned. We can test for an empty string by using the String class's length property. Since any non-zero value would evaluate to true, the exclamation point (!) in front of the length property would cause the function to exit on a zero length string.

The RegExp test() function checks for quotes around the responseText, indicating an error encountered in the servlet. Recall that we return JSONException messages from the AutocompleteServlet as a quote-delimited string. The String class's built-in replace() function is used to remove the quotes, so we can display the error message in an alert box. I returned it as a string for simplicity, but a more complex error object, such as one that contains an error number and level would work well as a JSONObject. The string can be displayed in a alert box directly. Originally, the intent was to use the eval() function on the responseText, but security concerns with the use of the eval() function within AJAX applications led me to abandon this approach in favor of this safer alternative.

Same goes for the list items, which are returned as an Array of JSONObjects. Rather than using the eval() function to create the JSONArray, we can use one of the many free parsers available. The one I used throws a SyntaxError exception, so we have to make the function call within a try/catch block.

A for loop is used to iterate through each item and add it to the list, in the appendFund() function.

Finally, the completeTable's visibility property is set to true to display the items:

[previous] [next]