jqGrid is an Ajax-enabled JavaScript control that provides solutions for representing and manipulating tabular data on the web.
Since the grid is a client-side solution loading data dynamically through Ajax callbacks, it can be integrated with any server-side technology, including PHP, ASP, Java Servlets, JSP, ColdFusion, and Perl. JqGrid is extremely robust, but with that comes a price; the amount of functionality available can often require a significant amount of configuration code, especially for tables incorporating some of the more advanced functionality… code that can end up being duplicated for every view that utilizes it.
The following blog post presents one solution for incorporating jqGrid into a Spring framework using Java in a manner that avoids a good portion of this duplication. jqGrid can be downloaded at www.trirand.com and installation is just a matter of copying files and folders to your web server or development directory.
Below is an example of a very basic jqGrid in JavaScript; it simply displays the data in a table, without providing any type of filtering, ordering, etc:
jQuery("#grid").jqGrid({ url:'<URL>', datatype: "json", colNames:['Inv No','Date','Client','Amount','Tax','Total','Notes'], colModel:[ {name:'id',index:'id', width:55}, {name:'invdate',index:'invdate', width:90}, {name:'name',index:'name asc, invdate', width:100}, {name:'amount',index:'amount', width:80, align:"right"}, {name:'tax',index:'tax', width:80, align:"right"}, {name:'total',index:'total', width:80,align:"right"}, {name:'note',index:'note', width:150, sortable:false} ], rowNum:10, rowList:[10,20,30], pager: '#pager2', sortname: 'id', viewrecords: true, sortorder: "desc", caption:"JSON Example" }); jQuery("#grid").jqGrid('mainNavGrid','#pager2',{edit:false,add:false,del:false});
Let’s start with the first variable piece of information, the URL property, which defines the destination when the grid makes a request for data. We start by creating a custom JavaScript tag called JQGridTag that extends javax.servlet.jsp.TagSupport. Within the doStartTag method, we create an instance of java.lang.StringBuilder, whose contents we will be writing out to the page’s output stream. The contents of this StringBuilder will contain the JavaScript jqGrid definition indicated above. So, we will end up with something like this.
@Override public int doStartTag() throws JspException { StringBuilder scriptBuilder = new StringBuilder(); scriptBuilder.append("<script type=\”text/javascript\”>"); scriptBuilder.append("jQuery(\"#list2\").jqGrid({"); scriptBuilder.append("url:'" + getGridURL() + "',"); scriptBuilder.append("datatype: \"json\","); scriptBuilder.append("colNames:['Inv No','Date','Client','Amount','Tax','Total', 'Notes'],"); scriptBuilder.append("colModel:["); scriptBuilder.append("{name:'id',index:'id', width:55},"); scriptBuilder.append("{name:'invdate',index:'invdate', width:90},"); scriptBuilder.append("{name:'name',index:'name asc, invdate',width:100},”); scriptBuilder.append("{name:'amount',index:'amount', width:80,align:\"right\"},"); scriptBuilder.append("{name:'tax',index:'tax', width:80, align:\"right\"},"); scriptBuilder.append("{name:'total',index:'total', width:80,align:\"right\"},"); scriptBuilder.append("{name:'note',index:'note', width:150, sortable:false}"); scriptBuilder.append("],"); scriptBuilder.append("rowNum:10,"); scriptBuilder.append("rowList:[10,20,30],"); scriptBuilder.append("pager: '#pager2',"); scriptBuilder.append("sortname: 'id',"); scriptBuilder.append("viewrecords: true,"); scriptBuilder.append("sortorder: \"desc\","); scriptBuilder.append("caption:\"JSON Example\""); scriptBuilder.append("});"); scriptBuilder.append("jQuery(\"#list2\").jqGrid('navGrid','#pager2',{edit:false, add:false,del:false});"); scriptBuilder.append("</script>"); try { pageContext.getOut().write(scriptBuilder.toString()); } catch (IOException ioe) { throw new JspException(ioe.getMessage()); } return EVAL_BODY_INCLUDE; }
Note the replacement of the URL property value definition with a method call. We have defined a gridURL attribute on our custom tag class. This method simply returns the value of that attribute, which is defined in the appropriate context xml, as follows. In applicationContext.xml, we will create a new group of settings to define the parameters of our grid:
<util:map id="examplePropertyMap"> <entry key="gridURL" value="/exampleURL"/> ... </util:map>
Now, we access this configuration data in our associated process controller:
@Controller() @RequestMapping("/exampleRequestMapping") public class ExampleProcessController { @Resource(name = "examplePropertyMap") private Map<String, Object> examplePropertyMap; … @RequestMapping(value = "/list") public ModelAndView getIt(@RequestParam Map<String, Object> map, HttpSession session, HttpServletRequest request){ ModelAndView modelAndView = new ModelAndView(“jqGrid”, map); String gridURL = (String) map.get(“gridURL”); modelAndView.addObject(“gridURL”, gridURL); … return modelAndView; } }
This allows the URL value to be passed to the custom JSP tag via a tag attribute so that we can apply it in the doStartTag method as seen in the jsGrid.jsp below:
<head> <sncc:jqgrid gridURL=”${gridURL}”/> </head> <body> <table id=”grid”><tr><td/></tr></table> <div id=”mainNavGrid”/> </body>
So, by simply making the gridURL property configurable, we are already well on our way to making the jqGrid a more generic solution. In my next blog post, we will explore these ideas further.
— Robert Rice, [email protected]