Ajax programming with Struts 2

Five steps to dynamic tables using Struts 2, Dojo and JSON

1 2 3 4 5 Page 5
Page 5 of 5

Ajax tables quick list

If you're looking for a quick list and some easy code that you can use to create an Ajax-style table using Struts 2, then here it is: Five steps to develop an Ajax-style table that dynamically sorts, filters, and paginates server-side data.

  1. Code a filter and two methods in a Struts 2/WebWork Action, returning a List of rows for the current page and the total row count:
    public class SortedPagedFilter {
    private byte direction; // direction of sorting
    private String field; // field to sort by
    private Map criteria; // filtering criteria
    private int page; // current page
    // accessors omitted
    }
    public class SomeAction extends ActionSupport {
    @SMDMethod
    public List<Some> getRows(SortedPagedFilter filter) {...}
    @SMDMethod
    public long getRowCount(SortedPagedFilter filter) {...}
    }
    
  2. Configure Struts 2:
    <package name="RPC" namespace="/nodecorate" extends="json-default">
    <action name="SomeListRpc" class="some.ActionClass"
    method="execute">
    <interceptor-ref
    name="json">
    
    <param name="enableSMD">true</param>
    </interceptor-ref>
    <result type="json">
    <param name="enableSMD">true</param>
    </result>
    </action>
    </package>
    
    
    
  3. Define a service, global currentPage variable, paging area, and table; import the Dojo required components onto a JSP page:
    <script type="text/javascript">
    var djConfig = { isDebug: false };
    </script>
    <script src="/MGA/struts/dojo/dojo.js"
    type="text/javascript"></script>
    
    <script type="text/javascript">
    dojo.req uire("dojo.rpc.*");
    dojo.req uire("dojo.widget.*");
    dojo.req uire("dojo.widget.FilteringTable");
    dojo.hostenv.writeIncludes();
    </script>
    <s:url id="smdUrl" namespace="/nodecorate" action="SomeListRpc"/>
    <script type="text/javascript">
    
    var currentPage = 0;
    var service = new dojo.rpc.JsonService("${smdUrl}");
    </script>
    
    First Name: <input type="text" id="filterFirstName">
    
    Second Name: <input type="text" id="filterSecondName">
    <button onclick="refreshData()">Search</button><br>
    <span id="testTablePagination"></span>
    
    <table class="filterable" dojoType="filteringTable" id="yourTableId"
    multiple="false" alternateRows="true" valueField="id">
    <thead>
    <tr>
    
    <th field="id" dataType="String">ID</th>
    <th field="firstName" dataType="String">First Name</th>
    <th field="secondName" dataType="String">Second Name</th>
    
    </tr>
    </thead>
    
    </table>
    
  4. Define the methods to handle data and page refreshes:
    <script type="text/javascript">
    refreshData = function() {
    // define a callback function for row data
    var rowsCallback = function(bean) {
    var yourTable = dojo.widget.byId('yourTableId');
    yourTable.store.setData(bean);
    };
    var yourTable = dojo.widget.byId('yourTableId');
    // construct a filter based on the current FilteringTable sort information
    var sortInfo = yourTable.sortInformation[0];
    var filter = {field:yourTable
    .columns[sortInfo.index].field,direction:sortInfo.direction,page:current
    Page};
    // add criteria to the filter, dynamically construct your own
    filter['criteria'] =
    {firstName:document.getElementById('filterFirstName').value,secondName:document.getElementById('filterSecondName').value};
    var deferred = service.getRows(filter);
    // start the RPC process
    deferred.addCallback(rowsCallback);
    var rowNumCallback = function(rowNumber) {
    var totalPages = Math.ceil(rowNumber / 20);
    // call your fillPagination function rendering pagination info
    fillPagination(totalPages);
    }
    // you don't need sort and page info to count rows, just filtering
    //criteria
    filter = {field:'',direction:1,page:0};
    filter['criteria'] =
    {firstName:document.getElementById('filterFirstName').value,
    secondName:document.getElementById('filterSecondName').value};
    var deferred = service.getRowCount(filter);
    // start the RPC process
    deferred.addCallback(rowNumCallback);
    }
    fillPagination = function(totalPages) {
    var el = document.getElementById('testTablePagination');
    el.innerHTML = 'Pages:&nbsp;';
    for(var i=0; i<totalPages; i++) {
    if(currentPage==i) {
    el.innerHTML += '<b>' + (i+1) + '</b>&nbsp;';
    } else {
    el.innerHTML += '<a href="#" onclick="currentPage=' + i + ';
    refreshData();">' + (i + 1) + '</a>&nbsp;';
    el.innerHTML += (i+1) + '</a>&nbsp;';
    }
    }
    }
    
    
    </script>
    
  5. Use Dojo aspects to replace FilteringTable's sort and click functionality:
    dojo.addOnLoad(function() {
    var yourTable = dojo.widget.byId('yourTableId');
    yourTable.createSorter = function() { return null;};
    dojo.event.connect("after", yourTable, "onSelect", function ()
    { onSelectFunc(); });
    dojo.event.connect("after", yourTable, "onSort", function ()
    { refreshData(); });
    });
    

In conclusion

In this article you've learned how to create dynamic, Ajax-style tables using Struts 2. The five-step solution in the quick list results in a simple table that sorts, filters and paginates server-side data. Coding on the server-side is more scalable (and more authentically dynamic) than a client-side solution, and using Struts 2 keeps you free of the programming constraints of a framework like GWT or Echo. Besides, Struts 2 provides all the Ajax development support you could want, doesn't it?

Oleg Mikheev is a Sun Certified Java Developer and IBM WebSphere Portal Developer with 10 years of experience with Java technologies. Oleg is currently employed as systems analyst by Gemini Systems, and is a postgraduate student at St.-Petersburg State Polytechnical University, Russia.

This story, "Ajax programming with Struts 2" was originally published by JavaWorld.

Copyright © 2007 IDG Communications, Inc.

1 2 3 4 5 Page 5
Page 5 of 5