Welcome!

AJAX & REA Authors: Lee Novak, Brad Abrams, Alin Irimie, Jonny Defh, RealWire News Distribution

Related Topics: AJAX & REA

AJAX & REA: Article

Real-World AJAX Book Preview: Post Changes to the Servlet

Real-World AJAX Book Preview: Post Changes to the Servlet

This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs for the special pre-order price, click here for more information. Aimed at everyone from enterprise developers to self-taught scripters, Real-World AJAX: Secrets of the Masters is the perfect book for anyone who wants to start developing AJAX applications.

Post Changes to the Servlet
In the MainPage-9.html, we add a new link called "Save" in the top toolbar. It's used to save the changes made by the user using an AJAX request.

Refer to the implementation of the "save" method in the MainPage-9.html. It constructs a request object. It sets the service specification using a "setServiceSpec" method. It also sets the "xmlDoc" of the request to the change list retrieved from the form. The "processRequest" method sends the service specification as one of the parameters of the URL request and "xmlDoc" as the body of the POST request. The "save" method and resulting URL request are shown in Listing 5.22.

Listing 5.22 - Save Changes

// called when the user clicks on the ‘save' button.
function save() {
   // retrieve changes as XML from the form
   var s = projectSummary.getChangeList();
   if (s == null || s == "") {
     // there are no new changes
     alert("There are no changes available to save");
   } else {
     // Changes are available
     //alert("The following changes are made by the user:\n" + s);
     // Construct an AJAX request
     var req = new DataRequest(svcURL, saveRequestCompleted,
       saveRequestFailed, saveRequestTimedout);
     // sets service specification
     req.setServiceSpec("ProjectService", "saveChanges");
     // sets XML document to be sent as the body of XML
     req.xmlDoc = s;
     // process the request
     ajaxEngine.processRequest(req);

     }
   }

   // called if the save request completes successfully
   function saveRequestCompleted(response) {
     alert("Save succeeded, the changes recorded in the form will be cleared");
     // since the changes have been saved, clear the recorded changes
     projectSummary.clearChanges();
   }

Let's examine the overall interaction using the following screensshots, URL, and XML documents.

Figure 5.7 shows the change list XML sent by the client in the request's body:

Below is the URL. Notice that the service specification is sent as one of the parameters of the URL. The name of the parameter is "service_spec."

http://localhost:8080/project?service_spec=<service name="ProjectService">
<method name="saveChanges"></method></service>&_=

The following is the service specification document received by the server:

<?xml version="1.0" encoding="UTF-8"?>
<service name="ProjectService"><method name="saveChanges"/></service>

The following is the XML document received by the server in the body of the POST request:

<?xml version="1.0" encoding="UTF-8"?>
<ChangeList>
   <Project id="1">
     <name>Marketing Campaign(2006)</name>
     <startDate>4/3/2006</startDate>
     <endDate>12/4/2006</endDate>
     <description>Draft - Marketing Campaign Project (2006). </description>
   </Project>
</ChangeList>

Notice that the XML documents on the client and the server are consistent. The server can process the XML documents as it wishes. This concludes our end-to-end discussion of an AJAX UI scenario. In the process we demonstrated how to structure AJAX pages (code) and how to make use of the MVC pattern for cohesive working of these pages.

Client-Side Renderer
We discussed the View implementation using an HTML template. This is a key reason that AJAX is such a compelling rich client technology. As the next step, it might be desirable to parameterize the templates so they can be applied repeatedly. This can be done in an AJAX UI, albeit differently. Once a pattern is standardized as an HTML template, JavaScript code can be used to render it in the client space based on a set of parameters.

Let's see this using an example that renders a form on the client side. The ProjectSummary.html is a form template. The HTML fragment that renders the form is shown below. It uses an HTML table element with two columns for the form. The first column displays the labels and the second column displays the fields.

<table id="projectSummaryElement" border="0" cellspacing="0" cellpadding="0">
   <tbody>
     <tr>
       <!—first label -->
       <td class="formLabelCell">Project Name:</td>
       <!—first field -->
       <td class="formFieldCell">
         <input type="text" id="name" class="FormField" style="width:400px" >
       </td>
     </tr>

     <tr>
       <!—second label -->
       <td class="formLabelCell">Start Date:</td>
       <!—second field -->
       <td class="formFieldCell">
         <input type="text" id="startDate" class="FormField"
style="width:150px" />
       </td>
     </tr>
     ... ... ... another row
     ... ... ... one more row
   </tbody>
</table>

We provide an additional method called "render" in our Form class to render the form based on the list of its components. The "render" method of the Form is shown in Listing 5.23.

Listing 5.23 - ‘Render' Method of Form

// renders Form's element on the client side
Form.prototype.render = function() {
   // table is the top level element of the Form.
   var table = document.createElement("table");
   table.border = "0";
   table.cellspacing = "0";
   table.cellpadding = "0";
   table.width = "100%";
   table.id = this.name;
   var tbody = document.createElement("tbody");
   table.appendChild(tbody);
   // For each field component create a row
   for (var i=0; i<this.components.length; i++) {
     var tr = document.createElement("tr");
     tbody.appendChild(tr);
     var comp = this.components[i];
     // if the component is not a TextAreaComp
     // add label using the display name of the comp.
     if (comp.type != "TextAreaComp") {
       // create cell for the label
       var td = document.createElement("td");
       td.style.width = "100px";
       // specify the css class name for the label cell
       td.className = "formLabelCell";
       td.appendChild(document.createTextNode(comp.displayName));
       tr.appendChild(td);
     }
     // create cell for the field
     td = document.createElement("td");
     td.className = "formFieldCell";
     // render the component by calling its ‘render'
     var elem = comp.render();
     if (comp.type == "TextAreaComp") {
       // text area spans across two columns
       elem.style.width="100%";
       td.colSpan = "2";
     } else {
       elem.style.width="200px";
     }
     elem.className = "FormField";
     // add the component's element to the cell
     td.appendChild(elem);
     // add the field cell to the row
     tr.appendChild(td);
   }
   this.element = table;
}

The following code shows the render method of one of the components (SelectComp). Refer to the source code for the implementation of the "render" method for other components.

Listing 5.24 - ‘Render' Method of SelectComp

SelectComp.prototype.render = function() {
   var elem;
   // create select element
   elem = document.createElement(‘select');
   // for each option, add option element
   if (this.options) {
     for (var i=0; i<this.options.length; i++) {
       var option = this.options[i];
       // create option element
       var oe = document.createElement("option");
       // set the value of the option element
       oe.value=option.value;
       // set the label of the option element
       oe.label = option.label;
       oe.appendChild(document.createTextNode(option.label));
       elem.appendChild(oe);
       }
     }
     this.element = elem;
     return elem;
   }

Based on the changes above, we can render our project summary form using JavaScript code without the HTML template. Refer to the ClientSideRenderer.html to see how a client-side renderer is used. The code that renders the form on the client side is shown in Listing 5.25.

Listing 5.25 - Client-Side Rendering of a Form

function initialize() {
// create a Form component
var projectSummary = new Form("projectSummaryForm");

   // set the field components of the form
   // specify the display name for each component
   projectSummary.setFieldComp(new TextComp("name", "Project Name:"));
   projectSummary.setFieldComp(new DateComp("startDate", "Start Date:"));
   projectSummary.setFieldComp(new DateComp("endDate", "End Date:"));

   // set a select component
   var sc = new SelectComp("status", "Status:");
   // set options for the select field
   sc.addOption("Green", "Green");
   sc.addOption("Yellow", "Yellow");
   sc.addOption("Red", "Red");
   sc.addOption("Not Started", "Not Started");
   projectSummary.setFieldComp(sc);

   projectSummary.setFieldComp(new TextComp("resource", "Resource:"));

   // add a text area field
   projectSummary.setFieldComp(new TextAreaComp("description", "Description:"));

   // now render the form
   projectSummary.render();
   // attch the rendered element of the form to MainArea
   attachElement("MainArea", projectSummary.element);
}

The resulting view using the client-side rendering is shown below.

Conclusion
HTML, CSS, JavaScript, and XML messages for information exchange provide a solid foundation for building a rich client user interface. Organizing and layering the views, models and controllers of the UI using the MVC pattern produces a reusable framework. It also facilitates independent development of views by a UI designer. Developers can work independently on models and controllers (application behavior). In the initial stages XML files can be used as the data source. This helps in firming up the data model and message formats. On the other hand, the server team can test the interaction with the UI using a browser. Such modular development and ease of integration are definitely going to boost the team's productivity.

Figure 5.8 summarizes the layering of the AJAX applications components discussed in this chapter.

Additional Information
Additional resources that you might refer to are listed below.

Acknowledgment
This chapter was inspired by Professor Niklaus Wirth's classic paper, "Program Development by Stepwise Refinement." My sincere gratitude to Professor Wirth for writing such a wonderful paper. My thanks are also due to the editor of this book Dion Hinchcliffe for the opportunity he created. And I would like to thank Dr. Ashish Tiwari, computer scientist at SRI, Palo Alto, CA, for his gracious help in reviewing the draft of this chapter and providing invaluable comments. My thanks are also due to my sons Abhineet and Praneet for being a sounding board for the content's clarity and keeping the environment around me cheerful and entertaining. Last, but not least, I would like to thank my lovely wife Rajshree for her patience and rock-solid support in all my endeavors. Finally, I dedicate this work to my loving mother Sita Sharma who is not with us anymore but her soul continues to guide me.

This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs, click here to order.

More Stories By Anil Sharma

Anil Sharma is a founder of Vertex Logic and architect of its AjaxFace product. He is working with Vertex Logic's customers and helping them deploy WEB 2.0 applications built using AjaxFace. These applications are in the areas of online printing, community WEB sites and social networking. He is driving future products of Vertex Logic. Prior to Vertex Logic, he was CTO and founder of Softrock Systems and Component Plus. There he built a model driven application platform using J2EE. His primary interests include user interface infrastructures and model driven applications. He is one of the contributors of the book "Real World AJAX - Secrets of the Master".

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.