Adding Ajax controls into existing JavaTM Platform, Enterprise Edition (Java EE) Web applications

Using the Dojo Toolkit, it is possible to embed JavaScriptTM controls that provide User Interface (UI) enhancements. These controls can be considered code snippets which help improve the responsiveness and appearance of the Web-site and are easy to integrate into static HTML, JavaServer Pages (JSP) files, JavaServer Faces (JSF) or server-side presentation renderings.

Example: Form Validation

Figure 1 is a typical display generated by a JSP file that has a user register with a site. After registration, the page validates that the fields are completed and passes the FORM to the server using an HTTP POST. Required fields are indicated by an asterisk. The page is static in that no feedback is provided that the user is correctly entering the information, or at least until the user clicks submit and the FORM is validated.


Figure 1. A Web site serving static Web content

Several items of interest included in the JSP code in listing 2. A large amount of JavasSript code exists at the top of the JSP file that is called to validate the format of input entries and ensure all required elements are provided. As an example, the code validates using the verifyZip() function to ensure that only numeric values are given. Additionally, checks for the phone number are made using the verifyPhone() function.


Listing 2. Registration JSP file
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="DC.LANGUAGE" scheme="rfc1766"/>

<link href="/PlantsByWebSphere/PlantMaster.css" rel="stylesheet" type="text/css"/>

<script type="text/javascript" src="/PlantsByWebSphere/applycss.js" language="JavaScript"></script>
<script>
function verifyForm(reginfo)
{
    if ((!exists(reginfo.userid.value)) ||
        (!exists(reginfo.passwd.value)) ||
        (!exists(reginfo.vpasswd.value)) ||
        (!exists(reginfo.fname.value)) ||
        (!exists(reginfo.lname.value)) ||
        (!exists(reginfo.addr1.value)) ||
        (!exists(reginfo.city.value)) ||
        (!exists(reginfo.state.value)) ||
        (!exists(reginfo.zip.value)) ||
        (!exists(reginfo.phone.value)))
   {
      alert("All required fields must be filled in.");
      return false;
   }
   else if (!verifyEmail(reginfo.userid.value)) {
       alert("E-mail Address is not valid.");
       return false;
   }
   else if (reginfo.passwd.value != reginfo.vpasswd.value)
   {
       alert("Passwords do not match.");
       return false;
   }
   else if (!verifyZip(reginfo.zip.value)) {
       alert("Zip Code is not valid.");
       return false;
   }
   else if (!verifyPhone(reginfo.phone.value)) {
       alert("Phone is not valid.");
       return false;
   }
   return true;
}

function exists(inputVal)
{
    var result = false;
    for (var i = 0; i <= inputVal.length; i++) {
        if ((inputVal.charAt(i) != " ") && (inputVal.charAt(i) != "")) {
            result = true;
            break;
        }
    }
    return result;
}

function verifyEmail(emailVal)
{
    var result = true;
    var foundAt = false;
    var foundDot = false;
    var atPos = -1;
    var dotPos = -1;
    for (var i = 0; i < emailVal.length; i++) {
        if (emailVal.charAt(i) == "@") {
            foundAt = true;
            atPos = i;
        }
        else if (emailVal.charAt(i) == ".") {
            foundDot = true;
            dotPos= i;
        }
    }
    if ((!foundAt) || (!foundDot) || (dotPos < atPos)) {
        result = false;
    }
    return result;
}

function verifyZip(zipVal)
{
    var result = false;
    for (var i = 0; i < zipVal.length; i++) {
        if (parseFloat(zipVal.charAt(i))) {
            result = true;
            break;
        }
    }
    return result;
}

function verifyPhone(phoneVal)
{
    var result = false;
    var cnt = 0;
    for (var i = 0; i < phoneVal.length; i++) {
        if (parseFloat(phoneVal.charAt(i))) {
            cnt++;
            if (cnt >= 7) {
                result = true;
                break;
            }
        }
    }
    return result;
}
</script>

</head>
<body class="work" >
<%
String formAction = "register";
com.ibm.websphere.samples.plantsbywebsphereejb.CustomerInfo customerInfo = 
      (com.ibm.websphere.samples.plantsbywebsphereejb.CustomerInfo) 
      request.getAttribute(com.ibm.websphere.samples.plantsbywebsphereejb.Util.ATTR_EDITACCOUNTINFO);
..........
..........
..........
%>
<form onsubmit="return verifyForm(this);" target="_self" name="reginfo" 
         method="POST" action="/PlantsByWebSphere/servlet/AccountServlet?action=<%=formAction%>">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
  <tr>
    <td><p class="trail"><a class="trail" class="footer" href="/PlantsByWebSphere/promo.html" target="work">Home</a> > <a class="trail" class="footer" href="/PlantsByWebSphere/login.jsp" target="work">Sign in</a></p></td>
  </tr>
  
  ............
  ............
  ............ 

<table border="0" cellpadding="0" cellspacing="0">
<caption>Contact Information</caption>
<colgroup>
<colgroup>
<colgroup>
<tbody>
  <tr>
    <td> </td>
    <td> </td>
    <td> </td>
  </tr>
  <tr>
    <td nowrap width="120"><p><label for="fname">First Name </label></td>
    <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td>
    <td width="100%"><p><input type="text" name="fname" value="<%=fname%>" size="20" id="fname"></p></td>
  </tr>
  <tr>
    <td nowrap><p><label for="lname">Last Name </label></td>
    <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td>
    <td width="100%"><p><input type="text" name="lname" value="<%=lname%>" size="20" id="lname"></p></td>
  </tr>
  <tr>
    <td nowrap><p><label for="addr1">Address Line 1 </label></td>
    <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td>
    <td width="100%"><p><input type="text" name="addr1" value="<%=addr1%>" size="20" id=addr1"></p></td>
  </tr>
  <tr>
    <td nowrap><p><label for="addr2">Address Line 2 </label></td>
    <td></td>
    <td><p><input type="text" name="addr2" value="<%=addr2%>" size="20" id="addr2"></p></td>
  </tr>
  <tr>
    <td nowrap><p><label for="city">City </label></td>
    <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td>
    <td><p><input type="text" name="city" value="<%=city%>" size="20" id="city"></p></td>
  </tr>
  <tr>
    <td nowrap><p><label for="state">State </label></td>
    <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td>
    <td><p><input type="text" name="state" value="<%=state%>" size="20" id="state"></p></td>
  </tr>
  <tr>
    <td nowrap><p><label for="zip">Zip Code </label></TD>
    <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td>
    <td><p><input type="text" name="zip" value="<%=zip%>" size="5" maxlength="10" id="zip"></p></td>
  </tr>
  <tr>
    <td nowrap><p><label for="phone">Phone (daytime) </label></td>
    <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td>
    <td><p><input type="text" name="phone" value="<%=phone%>" size="14" maxlength="14" id="phone"></p></td>
  </tr>
  <tr><td> <br> </td></tr>

  ...........
  ...........
                     
  </tbody>
</table>
<br>
          </td>
        </tr>
      </table><br>
    </td>
  </tr>
</table>

The goal is to improve the usability of the FORM, while having to maintain less code. Among many widgets, the Dojo Toolkit provides a library that you can use to validate INPUT fields for correct content. In addition, the form provides visual feedback that the form is entered correctly. Figure 2 shows the reworked registration page. Notice the addition of a 'Enter name' message on the right. When a user completes the Input field, the 'Enter name' message is removed, and the field is green to indicate that the entry is correct. On the zip code field, where an additional digit is entered, the entry is highlighted in red and an invalid message is displayed. As the user interacts with the form, the feedback is immediate.


Figure 2. Registration page using Ajax

Listing 2 shows the same JSP file previously provided with additional Ajax scripting added to improve the usability of the UI. In the <script> section, the Dojo Toolkit is added. The Dojo Toolkit contains a number libraries and by using the dojo.require option you specifiy which library to use. In this case the validation library is used with the necessary supporting libraries. The validation library is customizable for colors, sizes, fonts, and other style sheet attributes. A number of settings are included in the <style> section. For the validation widget to take affect, you must specify which controls need validation. The dojoType="ValidationTextBox" specifies the type of valiation and the attributes. In this case the attributes are required="true", propercase="true", and the promptmessage="* required". The propercase attribute specifies that the first character is in uppercase. If you type a lower case letter for your name, then the validation widget changes it to uppercase. Some of the validation widgets are unique. Client validation does not replace the need to validate on the server, but eliminates the number of round trip exchanges between the client and server before the data is correct.


Listing 2. Registration JSP with Ajax to the FORM

<html> <head> <title></title> <script type="text/javascript" src="/PlantsByWebSphere/applycss.js" language="JavaScript"> </script> <script type="text/javascript" src="/PlantsByWebSphere//dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true, extraLocale: ['de-de', 'en-us']"> </script> <script type="text/javascript"> dojo.require("dijit.form.TextBox"); dojo.require("dijit.form.ValidationTextBox"); dojo.require("dijit.form.NumberTextBox"); dojo.require("dijit.form.CurrencyTextBox"); dojo.require("dijit.form.DateTextBox"); dojo.require("dijit.form.TimeTextBox"); ...... ...... dojo.require("dojo.parser"); // scan page for widgets and instantiate them </script> <style> @import "/PlantsByWebSphere/dijit/themes/tundra/tundra.css"; span.invalid, span.missing { display: inline; margin-left: 1em; font-weight: bold; font-style: italic; font-family: Arial, Verdana, sans-serif; color: #f66; font-size: 0.9em; } .errorMessage { font-weight:bold; font-family:Arial, Verdana, sans-serif; color:#ff0000; font-size:0.9em; } .warningMessage { font-weight:bold; font-family:Arial, Verdana, sans-serif; color:#ff9900; font-size:0.9em; } .noticeMessage { font-weight: normal; font-family:Arial, Verdana, sans-serif; color:#663; font-size:0.9em;} .medium.dojoValidateEmpty { background-color: #FFFFFF; </style> </head> <body CLASS="tundra"> <% com.ibm.websphere.samples.plantsbywebsphereejb.CustomerInfo customerInfo = (com.ibm.websphere.samples.plantsbywebsphereejb.CustomerInfo) session.getAttribute(com.ibm.websphere.samples.plantsbywebsphereejb.Util.ATTR_CUSTOMER); String[] shippingMethods = com.ibm.websphere.samples.plantsbywebsphereejb.Util.getFullShippingMethodStrings(); %> <form onsubmit="return verifyForm(this);" target="_self" name="billship" method="post" action="/PlantsByWebSphere/servlet/ShoppingServlet?action=orderinfodone"> <table border="0" cellpadding="0" cellspacing="5" width="100%"> ....... ....... ....... <tr> <td colspan="3"> <table cellpadding="0" cellspacing="3" border="0" width="100%"> <tr> <td colspan="3"> <table border="0" cellpadding="0" cellspacing="5"> <h4 align="left"><B>1. Billing Address</B></h4> <colgroup class="label"> <colgroup> <colgroup> </TD> </tr> </table> <table cellpadding="0" cellspacing="5" border="0" width="100%"> <tr> <td nowrap width="120"> <P> <label for="bname"> Full Name  </label> </td> <TD><IMG border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></TD> <TD width="100%"> <P> <input id="bname" type="text" name="bname" class="medium" value="<%= customerInfo.getFirstName() + " " + customerInfo.getLastName()%>" dojoType="dijit.form.ValidationTextBox" propercase="true" required="true" promptMessage="Enter Name" /> </P> </TD> </tr> <tr> <td nowrap width="120"> <p> <label for="baddr1"> Address Line 1  </label> </td> <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td> <td width="100%"> <p> <input type="text" id="baddr1" name="baddr1" class="medium" value="<%= customerInfo.getAddr1() %>" dojoType="dijit.form.ValidationTextBox" lowercase="false" required="true" promptMessage="Enter Address" /> </p> </td> </tr> <tr> <td nowrap> <p> <label for="baddr2"> Address Line 2  </label> </td> <td></td> <!-- <td><p><input type="text" id="baddr2" name="baddr2" class="medium" value="<%= customerInfo.getAddr2() %>"></p></td> --> <td width="100%"> <p> <input type="text" id="baddr2" name="baddr2" class="medium" value="<%= customerInfo.getAddr2() %>" dojoType="dijit.form.ValidationTextBox" lowercase="false" required="false" promptMessage="Enter Address" /> </p> </td> </tr> <tr> <td nowrap> <p> <label for="bcity"> City  </label> </td> <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td> <td> <p> <input type="text" id="bcity" name="bcity" class="medium" value="<%= customerInfo.getAddrCity() %>" dojoType="dijit.form.ValidationTextBox" lowercase="false" required="true" promptMessage="Enter City" /> </P> </TD> </tr> <tr> <td nowrap> <p> <label for="bstate"> State  </label> </td> <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td> <td width="100%"> <p> <input type="text" id="bstate" name="bstate" class="medium" value="<%= customerInfo.getAddrState() %>" dojoType="dijit.form.ValidationTextBox" uppercase="true" required="true" promptMessage="Enter State" /> </P> </TD> </p> </td> </tr> <tr> <td nowrap> <p> <label for="bzip"> Zip Code  </label> </td> <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td> <td> <p> <input type="text" id="bzip" name="bzip" class="medium" value="<%= customerInfo.getAddrZip() %>" dojoType="dijit.form.NumberTextBox" size="5" maxlength="9" required="true" places="9" promptMessage="Enter ZipCode" /> </p> </td> </tr> <tr> <td nowrap> <p> <label for="bphone"> Phone (daytime)  </label> </td> <td><img border="0" src="/PlantsByWebSphere/images/required.gif" width="10" height="15" alt="Required indicator"></td> <td width="100%"> <p> <input type="text" id="bphone" name="bphone" class="medium" value="<%= customerInfo.getPhone() %>" dojoType="dijit.form.ValidationTextBox" lowercase="false" required="true" promptMessage="Enter Phone"/> </p> </td> </tr> </table> </td> ...... ...... ...... </body> </html>