Using Ajax with Struts
— print (last updated: Oct 11, 2009) print

Select font size:

Create the example

This example illustrates two presentations of a simple form with textfield whose parameter is "name", allowing us to use the generated ActionForm Beans essentially "as is." The first form, in textfield.jsp, uses the standard Struts setup. The second form, in textfield-ajax.jsp, illustrates the Ajax activation.

Download the StrutsAjax.zip archive. For faster usage, extract the StrutsAjax directory, move it to the NetBeans projects folder and install it as web application with existing sources. After installation, add the Struts library.

Otherwise, you can create the application from the pieces as indicated by these steps:
  1. Create web application StrutsAjax using the Struts framework.
  2. Copy prototype.js into the web (Web Pages) directory.
  3. Create these JSP files (alternatively, copy the web/*.jsp files from the archive into the project web directory):

    index.jsp
    <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Index</title> </head> <body> <%@ include file="nav.jsp" %> <h2>Index</h2> </body> </html>

    nav.jsp
    <html:link action="/index" >index</html:link> &nbsp;&nbsp; <html:link action="/textfield" >Textfield</html:link> &nbsp;&nbsp; <html:link action="/textfield-ajax" >Textfield-Ajax</html:link>

    textfield.jsp
    <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %> <c:set var="page_title" value="Non-Ajax Form" /> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${page_title}</title> </head> <body> <%@ include file="nav.jsp" %> <h2>${page_title}</h2> <html:form action="/tf_handler"> name: <html:text property="name" /> <br /> <html:submit value="Go" /> </html:form> <html:errors /> </body> </html>

    textfield-ajax.jsp
    <%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %> <c:set var="page_title" value="Ajax Form" /> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>${page_title}</title> <script type="text/javascript" src="${pageContext.request.contextPath}/prototype.js"></script> <script type="text/javascript"> function tf() { new Ajax.Request( '${pageContext.request.contextPath}/tf_ajax_handler.do', { method: 'get', parameters: $('tf').serialize(true), onSuccess: function(xhrq) { var response = xhrq.responseText || "no response text"; $('resp').innerHTML = response }, onFailure: function(){ alert('Something went wrong...') } } ); } </script> </head> <body> <%@ include file="nav.jsp" %> <h2>${page_title}</h2> <html:form action="/tf_ajax_handler" onsubmit="tf();return false;" styleId="tf" > name: <html:text property="name" /> <br /> <html:submit value="Go" /> </html:form> <div id="resp"></div> </body> </html>

    ajax-out.jsp
    <%@taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %> <%@taglib prefix="logic" uri="http://jakarta.apache.org/struts/tags-logic" %> <logic:messagesNotPresent> name: ${param.name} </logic:messagesNotPresent> <html:errors />
  4. Create the classes controller.TfHandler and controller.TfAjaxHandler as a Struts ActionForm Bean classes.
  5. Create associated Struts Action classes controller.TfAction, with session scope.
  6. The only modification to the Java files are to controller/TfHandler.java and controller/TfAjaxHandler.java In both of these, replace the default created statement in validate:
    errors.add("name", new ActionMessage("error.name.required"));
    
    by
    errors.add("name", new ActionMessage("errors.required", "name"));
    
    This allows us to use the already-existing messages in ApplicationResource.properties. and avoid modifying this file.
  7. Make these modifications/additions to the action tags in struts-config.xml:
        <action-mappings>
            <action 
                input="/textfield.jsp" 
                name="TfHandler" 
                path="/tf_handler" 
                scope="session" 
                type="controller.TfAction">
              <forward name="success" path="/textfield.jsp"/>
            </action>
            
            <action 
                input="/ajax-out.jsp" 
                name="TfAjaxHandler" 
                path="/tf_ajax_handler" 
                scope="session" 
                type="controller.TfAction">
              <forward name="success" path="/ajax-out.jsp"/>
            </action>
            
            <action path="/textfield" forward="/textfield.jsp"/>
            <action path="/textfield-ajax" forward="/textfield-ajax.jsp"/>
            <action path="/index" forward="/index.jsp"/>
    
        </action-mappings>
    One observation to make is that both /tf_handler and /tf_ajax_handler use the same controller.TfAction class which would make generating the Ajax action trick using the NetBeans wizards.
Finally, run the StrutsAjax project. When you run it, test out the effects of submission with empty and non-empty values in the field.

Discussion of the Ajax setup

  1. The form declaration is this.
    <html:form action="/tf_ajax_handler" onsubmit="tf();return false;" 
         styleId="tf" >
    
    The action is not actually called. This is because when the form is submitted the JavaScript function tf() is called. The final return false statement ensures that the action is not called.

    The reason we need action="/tf_ajax_handler" is so that Struts requires it so that it can match the form activatation with the TfAjaxHandler ActionForm Bean using information in the action mapping in the struts-config.xml file.
  2. The JavaScript function call is this:
    function tf() {
      new Ajax.Request(
        '${pageContext.request.contextPath}/tf_ajax_handler.do', 
        {
          method: 'get',
          parameters: $('tf').serialize(true),
          onSuccess: function(xhrq) {
                       var response = xhrq.responseText || "no response text";
                       $('resp').innerHTML = response
                     },
          onFailure: function(){ alert('Something went wrong...') }
        }
      );
    }
    
    Note that we must call the /tf_ajax_handler action in a very strict way, expression the full path to it, along with the ".do" extension.

    The form's id, which is tf, is expressed by the Struts styleId attribute (a misnomer!). Using this id value, the parameter are all passed via the option:
    parameters: $('tf').serialize(true),
    
    Upon server-side complete, the server response is placed in the div below the form:
    <div id="resp"></div>
    
  3. The action for the Ajax call is this:
            <action 
                input="/ajax-out.jsp" 
                name="TfAjaxHandler" 
                path="/tf_ajax_handler" 
                scope="session" 
                type="controller.TfAction">
              <forward name="success" path="/ajax-out.jsp"/>
            </action>
    
    This ensures that in all cases, whether success is achieved (and forward is used) or not (validation fails and input is used), that the Ajax server-side call will call the script ajax-out.jsp
  4. The ajax-out.jsp,
    <%@taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %>
    <%@taglib prefix="logic" uri="http://jakarta.apache.org/struts/tags-logic" %>
    <logic:messagesNotPresent>
      name: ${param.name}
    </logic:messagesNotPresent>
    <html:errors />
    
    permits the desired behavior to happen and be presented in the div below the form. If success is reached, the html:errors tag is empty and the logic:messagesNotPresent will be active, allowing us to display the body.

    If validation fails, and there are errors, the logic:messagesNotPresent will be inactive and html:errors will display the errors.


© Robert M. Kline