Hack 7. Receive Data in JSON Format
Ajax can receive data in efficient and powerful JavaScript Object Notation. How would you like to use Ajax and receive data from the server as plain old JavaScript objects? Well, you can, using a format called JavaScript Object Notation (JSON). This hack takes information entered by a web user and initiates a server round trip, which returns the data in JSON syntax for the web page's use. JSON is simple and straightforward, which is probably why a lot of developers like it. JSON-formatted data is appropriate for simple objects that are bundles of properties and values. An example is a server program that pulls product information from a database or cache and returns it to a retail web page in JSON format. Data in JSON format is represented by:
The values of each property in the object can be:
This is exactly the format of an Object literal in JavaScript. As an example, here is what the information requested of the user in "Use the Request Object to POST Data to the Server" [Hack #2] looks like in JSON format: { firstname:"Bruce", lastname:"Perry", gender:"M", country:"USA" } Magic JSONIn this section, we'll use a similar HTML page to the one used in "Use the Request Object to POST Data to the Server" [Hack #2], and we'll ask the user for the same information; however, this hack uses JavaScript code and Ajax to handle a JSON return value from the server. Two div elements at the bottom of the HTML page show the JSON return value from the server and then display the object's properties and values in a more friendly fashion. Here's the code for the HTML page: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"> <html> <head> <script type="text/javascript" src="js/hack5.js"></script> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>Receive JSON response</title> </head> <body> <h3>A Few Facts About Yourself...</h3> <form action="javascript:void%200" onsubmit="sendData( );return false"> <p>First name: <input type="text" name="firstname" size="20"> </p> <p>Last name: <input type="text" name="lastname" size="20"> </p> <p>Gender: <input type="text" name="gender" size="2"> </p> <p>Country of origin: <input type="text" name="country" size="20"> </p> <p><button type="submit">Send Data</button></p> <div id="json"></div> <div id="props"></div> </form> </body> </html> Figure 1-9 shows what the web page looks like. Figure 1-9. JSON is calling![]() The JavaScript code is imported by the script tag and specified by the file hack5.js. The JavaScript sends the user's entered values to the server; because this was discussed in "Use the Request Object to POST Data to the Server" [Hack #2] and other hacks, the code is reproduced here but doesn't go into great detail.
Here's the code for this hack. Below, we'll go over the key parts that handle the return value as a JavaScript object. var request; var queryString; //will hold the POSTed data function sendData( ){ setQueryString( ); url="http://localhost:8080/parkerriver/s/json"; httpRequest("POST",url,true); } //event handler for XMLHttpRequest function handleJson( ){ if(request.readyState == 4){ if(request.status == 200){ var resp = request.responseText; var func = new Function("return "+resp); var objt = func( ); var div = document.getElementById("json"); stylizeDiv(resp,div); div = document.getElementById("props"); div.innerHTML="<h4>In object form...</h4>"+ "<h5>Properties</h5>firstname= "+ objt.firstname +"<br />lastname="+ objt.lastname+ "<br />gender="+ objt.gender+ "<br />country="+ objt.country; } else { alert("A problem occurred with communicating between "+ "the XMLHttpRequest object and the server program."); } }//end outer if } /* Initialize a request object that is already constructed */ function initReq(reqType,url,bool){ /* Specify the function that will handle the HTTP response */ request.onreadystatechange=handleJson; request.open(reqType,url,bool); request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); request.send(queryString); } /* Wrapper function for constructing a request object. Parameters: reqType: The HTTP request type, such as GET or POST. url: The URL of the server program. asynch: Whether to send the request asynchronously or not. */ function httpRequest(reqType,url,asynch){ //Snipped... See Hack #1 or #2 } function setQueryString( ){ queryString=""; var frm = document.forms[0]; var numberElements = frm.elements.length; for(var i = 0; i < numberElements; i++){ if(i < numberElements-1){ queryString += frm.elements[i].name+"="+ encodeURIComponent(frm.elements[i].value)+"&"; } else { queryString += frm.elements[i].name+"="+ encodeURIComponent(frm.elements[i].value); } } } function stylizeDiv(bdyTxt,div){ //reset DIV content div.innerHTML=" "; div.style.fontSize="1.2em"; div.style.backgroundColor="yellow"; div.appendChild(document.createTextNode(bdyTxt)); } As in this chapter's previous hacks, the initReq( ) function initializes the request object and sends an HTTP request to the server. The event-handling function for when the response is ready is called handleJson( ). The response is a JSON-formatted text string, as opposed to XML or some other text type. As is, JavaScript interprets this returned text as a string object. Therefore, the code initiates an opening step before the server's return value is interpreted as a JavaScript object literal. (By the way, in this hack, the server takes the request parameters and reformats the parameter names and property values into JSON syntax, prior to sending the reformatted data as its response.)
Within the handleJson( ) code (highlighted in the previous code sample), the variable resp refers to the HTTP response text, which JavaScript interprets as a string. The interesting stuff occurs in the Function constructor: var func = new Function("return "+resp); This code creates a new Function object on the fly and stores the Function in a variable named func. JavaScript coders might note that most functions are predefined and declared in code, or created as function literals. However, in this case we need to define a function body dynamically using a string, and the Function constructor provides the perfect tool.
The next line creates a function that returns an object literal, representing the server return value. You then call the function and use the returned object to dynamically display server values on the web page with DOM programming (all without complex object serialization or a page refresh!): var objt = func( ); var div = document.getElementById("json"); stylizeDiv(resp,div); div = document.getElementById("props"); div.innerHTML="<h4>In object form...</h4><h5>Properties</h5>firstname= "+ objt.firstname +"<br />lastname="+ objt.lastname+ "<br />gender="+ objt.gender+ "<br />country="+ objt.country; A variable named objt stores the object literal. The values are pulled from the object with syntax such as objt.firstname. Figure 1-10 shows what the web page looks like after it has received a response. Figure 1-10. Visualizing JavaScript properties is sweet!![]() On the Server SideA Java servlet handles requests for this hack. For those interested in the server activity, here is the doPost( ) method for this code: protected void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { Map valMap = httpServletRequest.getParameterMap( ); StringBuffer body = new StringBuffer("{\\n"); if(valMap != null) { String val=null; String key = null; Map.Entry me = null; Set entries = valMap.entrySet( ); int size = entries.size( ); int counter=0; for(Iterator iter= entries.iterator( );iter.hasNext( );) { counter++; me=(Map.Entry) iter.next( ); val= ((String[])me.getValue( ))[0]; key = (String) me.getKey( ); if(counter < size) { body.append(key).append(":\\"").append(val).append("\\",\\n"); } else { //remove comma for last entry body.append(key).append(":\\"").append(val).append("\\"\\n"); } } } body.append("}"); AjaxUtil.sendText(httpServletResponse,body.toString( )); } The AjaxUtil class sends the HTTP response with a Content-Type of text/plain; charset=UTF-8. Some web sites have discussed using a Content-Type of application/x-json for JSON, but as of this writing, developers and standards bodies have not yet settled on a standard relating to this matter. The AjaxUtil class also sets the HTTP response header Cache-Control to no-cache, which tells the browser or user agent not to cache the responses: response.setHeader("Cache-Control", "no-cache"); |