Hack 14. Submit Selection-List Values to the Server Without a Round Trip


Whisk the user's multiple list choices off to the server without delay.

Many web developers will see the advantage of sending a user's multiple choices in a radio button or select list directly to a server program using the request object, rather than requiring the user to click a button and send the entire form. This gives the application greater responsiveness and increases efficiency by sending discrete values rather than clumps of information.

This hack sends the user's choices of U.S. states to a server program when the keyboard focus is moved away from the select list. The select element looks like this in the HTML code that underlies the web page:

<select name="_state" multiple="multiple" size="4">

This is a selection list that allows the user to choose more than one item. When the keyboard focus moves from the select list (because the user presses the Tab key or clicks elsewhere on the page), the code defined by the element's onblur event handler executes. (This code is shown in an upcoming section.) The size=4 part indicates that four state names can be displayed at a time in the select list. Figure 2-4 shows the page loaded into the Safari browser.

Figure 2-4. Multiple choices for immediate delivery


A JavaScript file named hacks_2_4.js declares all the code this hack needs. Here is the HTML for the web page, which imports this file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"         "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head>     <meta http-equiv="content-type" content="text/html; charset=utf-8" />     <script type="text/javascript" src="/books/4/254/1/html/2/js/hacks_2_4.js"></script>     <link rel="stylesheet" type="text/css" href="/css/hacks.css" />     <title>Alter select lists</title> </head> <body> <h3>Create or Alter a Select List</h3> <form action="javascript:void%200" >     <table border="0">         <tr><td>Choose one or more states: </td><td>          <select name="_state" multiple="multiple" size="4">             <option value="al">Alabama</option>             <option value="ak">Alaska</option>             <option value="az">Arizona</option>             <option value="ar">Arkansas</option>             <option value="ca">California</option>             <option value="co">Colorado</option>             <option value="ct">Connecticut</option>             <option value="de">Delaware</option>             <option value="dc">District of Columbia</option>             <option value="fl">Florida</option>             <option value="ga">Georgia</option>             <option value="hi">Hawaii</option>             <!snipped...-->         </select></td></tr>         <tr><td><span  class=                 "message">The server reports that you have chosen the                  following abbreviated states: </span>         <tr><td>Choose your list content:</td>         <td>European countries:          <input type="radio" name="countryType"  value="euro" />          South American countries:          <input type="radio" name="countryType"  value="southam" />         </td></tr>         <tr><td><div ></div></td></tr>     </table></form> </body> </html>

A span element contains a message the user sees after making some choices in the select list. This message is styled by a CSS rule in the file hacks.css. We'll take a look at the message returned to the user momentarily, but first let's examine the code that submits the user's choices to a server. The code is a little complicated at first glance, but stay with it because what it accomplishes is really quite simple:

function getSelectInfo(selectObj){     if (selectObj == null) { return; }     formObj=selectObj;     formObjTyp =formObj.tagName.toLowerCase(  );     var optsArray = formObj.options;     var selectedArray = new Array(  );     var val = "";     //store selected options in an Array     for(var i=0,j=0; i < optsArray.length; i++){         if(optsArray[i].selected) {             selectedArray[j]=optsArray[i].value;             j++;         }     }     //create a comma-separated list of each      //selected option value     for(var k = 0; k < selectedArray.length; k++){         if(k !=selectedArray.length-1 ) { val +=selectedArray[k]+",";}         else {val +=selectedArray[k]; }     }     var url = "http://www.parkerriver.com/s/webforms?objtype="+               encodeURIComponent(formObjTyp)+"&val="+     encodeURIComponent(val);     httpRequest("GET",url,true); }

The code takes all of the options associated with the select element and determines which of them the user has selected. These options represent the user's choice(s) of U.S. states. The code takes each selected option and stores it in a string, separated by commas (if there is more than one choice), as follows: ma,nh,vt.

This task would be easier if the browser stored the selected values in one convenient place, such as a value property of the select object, but this isn't the case! You have to grab all the options, determine which ones were selected, and store those somewhere, such as in a JavaScript array.

A select element contains option elements, as in:

<select name="_states">
<option value="vt">Vermont</option>
...
</select>

In the DOM, the select element is represented by a select object that has an options property, an array of option objects. You get the value of each option, which the user sees as words in a list (e.g., "Vermont") using the value property of an option object. Phewfun to code, but it involves endless objects and properties!


The server component is expecting an objtype parameter, which in this case equals "select." We are also sending the string of comma-separated choices, pointed to by the val parameter (we could just as easily have used spaces, colons, or some other delimiter to separate each choice). Because we are using JavaScript's global function encodeURIComponent( ), each comma is encoded into %2C, since certain punctuation marks are not allowed in the character strings that are sent to server components.

encodeURIComponent( ) is a global function that is designed to encode portions of a uniform resource indicator (URI), which is a fancy name for the addresses you enter into a browser's location field to download a web page. This function encodes punctuation characters that have special purposes in URIs, such as /, :, @, and ;, as well as space characters, into their hexadecimal equivalents. For example, a ; character is encoded into %3B. encodeURIComponent( ) does not encode ASCII numbers or letters. Use encodeURIComponent( ) to encode query strings or path information that your JavaScript code is handling.


Here is an example of a URL sent by the previous JavaScript:

http://www.parkerriver.com/s/webforms?objtype=select&val=ma%2Cvt%2Cny

This URL contains ma, vt, and ny as choices; after the val parameter is decoded, it will read ma,vt,ny.

Now What Happens?

The server grabs the selected values and redirects them back to the application, with some extra information. This is where the displayed message comes to the fore. It displays the user's current choices and some information about the server with which the application is connected. Figure 2-5 shows the web page after the user has made some choices and moved the keyboard focus from the select list.

Figure 2-5. Instant feedback on list choices


The message changes dynamically without anything else being rebuilt or refreshed on the web page. It gives the user instant feedback while connected to a server, without any browser round trips. How does this work? Here is the JavaScript for the handleResponse( ) function, which deals with the server return value. I have highlighted only the code that converts the return value into the user message:

//event handler for XMLHttpRequest function handleResponse(  ){     try{         if(request.readyState == 4){             if(request.status == 200){                 if(formObjTyp.length > 0 && formObjTyp == "input"){                 //working with existing radio button                     var resp =  request.responseText;                     //return value is an array                     var func = new Function("return "+resp);                     var objt = func(  );                     var sel = document.createElement("select");                     sel.setAttribute("name","countries");                     createOptions(sel,objt);                     var newsel = document.getElementById("newsel");                     reset(newsel);                     newsel.appendChild(sel);                 } else  if(formObjTyp.length > 0 && formObjTyp == "select"){                     var resp =  request.responseText;                     //return value is a JSON object literal                     var func = new Function("return "+resp);                     var objt = func(  );                     var fld = document.getElementById("select_info");                     if(fld != null){                         fld.innerHTML = "The server <strong>"+
objt.Server_info+ "</strong> reports that you have chosen"+ "<br /> the following "+ "abbreviated states: <strong>"+ objt.Selected_options+"</strong>"; } } } else { //request.status is 503 //if the application isn't available; //500 if the application has a bug alert( "A problem occurred with communicating "+ "between the XMLHttpRequest object and the "+ "server program."); } }//end outer if } catch (err) { alert("It does not appear that the server "+ "is available for this application. Please"+ " try again very soon. \\nError: "+err.message); } }

Hello Again, JSON

The server provides its answer in JSON format [Hack #7] as a string that can easily be converted by the client-side browser code into a JavaScript object. An example of a server return value, which some readers may recognize as an object literal, is:

{ Server_info: "Apache Tomcat/5.0.19", Selected_options: "vt ny nh ma" }

This code represents an object that has two properties, Server_info and Selected_options. To derive the property values from the object, you use the "dot" syntax, as in obj.Selected_options. If the obj variable is set to the prior code's object literal, the latter code line returns "vt ny nh ma". ("Receive Data in JSON Format" [Hack #7] describes the JavaScript code to use for sending and handling JSON syntax.)

A Dabble of Server-Side

For those interested in one method of sending JSON-formatted values back to Ajax, here is a Java method that is used for this hack. This method takes as parameters the property names and values in a string, and the character, such as a comma, that separates the property names from the values:

public static String getJsonFormat(String propValues, String delim) {     if(propValues == null || propValues.length(  )==0) { return "";}     StringBuffer structure = new StringBuffer("");     structure.append("{\\n");     if (delim == null || delim.length(  ) == 0) { delim = ",";}     /* We're expecting comma-separated values such as prop1,val1,     prop2,val2, etc. */     StringTokenizer toke = new StringTokenizer(propValues,delim);     int j = 0;     int c =  toke.countTokens(  );     for(int i = 1; i <=c; i++) {         j = i%2;         if(j != 0) { structure.append(toke.nextToken(  )).                 append(": ");   } //it's a property name         else { structure.append("\\"").append(toke.nextToken(  )).                 append("\\""); //it's a property value             if(i != c){structure.append(",");}             structure.append("\\n");         }     }     structure.append("}");     return structure.toString(  ); }

If the Java servlet calls the method this way:

getJsonFormat("Server_info,Apache Tomcat,Selected_options,ca ma nh ny",",")

the method returns:

{ Server_info: "Apache Tomcat", Selected_options: "ca ma nh ny" }

The DOM API

This hack's next step is to store this return value in a variable, so the JavaScript can display its value to the user:

var func = new Function("return "+resp); var objt = func(  ); var fld = document.getElementById("select_info");

"Receive Data in JSON Format" [Hack #7] explains this use of the Function constructor to take advantage of the JSON format. Here, suffice it to say that the variable objt now contains the properties/values that interest us.

The variable fld represents the div element we reserved on the HTML page for containing this user message from the server. getElementById( ) is a DOM API method for getting a reference to a tag in HTML code, so the code can change its behavior or alter its appearance:

if(fld != null){     fld.innerHTML = "The server <strong>"+objt.Server_info+                     "</strong> reports that you have chosen"+                     "<br /> the following "+                     "abbreviated states: <strong>"+                     objt.Selected_options+"</strong>"; }

Easily display the object's information using syntax such as objt.Selected_options. As you saw in Figure 2-4, the states that the user has chosen and the name of the server software are displayed dynamically. The message changes automatically as the user makes different selections in the list. The information is derived from a server rather than just being generated by client-side JavaScript.




Ajax Hacks
Ajax Hacks: Tips & Tools for Creating Responsive Web Sites
ISBN: 0596101694
EAN: 2147483647
Year: 2006
Pages: 138

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net