Friday, September 16, 2011

Spring MVC: Integrating MySQL, MongoDB, RabbitMQ, and AJAX - Part 1: jQgrid View

Review

In the previous section, we've managed to create the core Event management system and use DataTables to display tabular data. In this section, we will use jQgrid, a jQuery plugin, to provide advance features to our table like sorting and searching.

Where am I?

Table of Contents

  1. Event Management
  2. Messaging support
  3. Error persistence
  4. Build and deploy

jQgrid View

As mentioned in the previous section, we will present tabular data using jQgrid and we'll add caching functionality to improve the application's performance. We'll utilize Spring Cache as our abstraction tool, and Ehcache as our cache storage.

What is jQgrid?
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 uses a jQuery Java Script Library and is written as plugin for that package. (Source: http://www.trirand.com/jqgridwiki/doku.php)

What is Ehcache?
Ehcache is an open source, standards-based cache used to boost performance, offload the database and simplify scalability. Ehcache is robust, proven and full-featured and this has made it the most widely-used Java-based cache. Source: http://ehcache.org/

Before we proceed with the development, let's preview the final output:

Development

Since we'll be adding caching functionality, we need to provide a custom controller, and since jQgrid requires a specific JSON format, we need to create a custom DTO. We shall divide this page as follows:
  1. Data Transfer Object (DTO)
  2. Controller
  3. JSP page

1. Data Transfer Object (DTO)

jQgrid can exchange and communicate data via different formats: XML, JSON, Arrays, and etc. We will use JSON as our data-interchange format because it's lightweight and flexible. In order for our JSON format to work, we need to create a custom data transfer object (DTO) that matches our jQgrid's JSON reader property.

Below is our jQgrid JSON reader declaration:
jsonReader : {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
cell: "cell",
id: "id"
}
view raw gistfile1.js hosted with ❤ by GitHub


We have to match those fields in our DTO (for an explanation of those fields, read the comments in the DTO). Consequently, we have the following class:

package org.krams.tutorial.dto;
import java.util.List;
/**
* A POJO representing a jQgrid's jsonReader property.
* This is mainly used as a DTO for the presentation layer.
*
* @see <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data">JSON Data</a>
*
* @author krams at {@link http://krams915@blogspot.com}
*/
public class JqgridTableDto<T extends Object> {
/**
* Current page of the query
*/
private String page;
/**
* Total pages for the query
*/
private String total;
/**
* Total number of records for the query
*/
private String records;
/**
* An array containing the actual data
*/
private List<T> rows;
public JqgridTableDto() {}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
public String getTotal() {
return total;
}
public void setTotal(String total) {
this.total = total;
}
public String getRecords() {
return records;
}
public void setRecords(String records) {
this.records = records;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
}


2. Controller

Next we will create a new controller to handle jQgrid-related requests with caching functionality:

package org.krams.tutorial.controller;
import java.util.List;
import org.krams.tutorial.domain.Event;
import org.krams.tutorial.dto.JqgridTableDto;
import org.krams.tutorial.dto.ResponseDto;
import org.krams.tutorial.service.IEventService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Controlling for handling event requests
*
* @author krams at {@link http://krams915@blogspot.com}
*/
@Controller
@RequestMapping("/jqgrid/event")
public class JqgridEventController {
@Autowired
private volatile IEventService service;
@RequestMapping
public String getEventPage() {
return "jqgrid/event-page";
}
@CacheEvict(value = "records", allEntries=true)
@RequestMapping(value = "/add", method = RequestMethod.POST)
public @ResponseBody ResponseDto<Event> add(Event event) {
if (service.create(event) != null) {
return new ResponseDto<Event>(true);
}
return new ResponseDto<Event>(false);
}
@CacheEvict(value = "records", allEntries=true)
@RequestMapping(value = "/edit", method = RequestMethod.POST)
public @ResponseBody ResponseDto<Event> edit(Event event) {
if (service.update(event) != null) {
return new ResponseDto<Event>(true);
}
return new ResponseDto<Event>(false);
}
@CacheEvict(value = "records", allEntries=true)
@RequestMapping(value = "/delete", method = RequestMethod.POST)
public @ResponseBody ResponseDto<Event> delete(Long id) {
if (service.delete(id) == null) {
return new ResponseDto<Event>(true);
}
return new ResponseDto<Event>(false);
}
@Cacheable(value = "records")
@RequestMapping(value = "/getall", method = RequestMethod.POST)
public @ResponseBody JqgridTableDto<Event> getall() {
List<Event> events = service.readAll();
if (events != null) {
JqgridTableDto<Event> response = new JqgridTableDto<Event>();
response.setRows(events);
response.setRecords(new Integer(events.size()).toString());
response.setTotal(new String("1"));
response.setPage(new String("1"));
return response;
}
return new JqgridTableDto<Event>();
}
}


We are re-using the same EventService for the DataTables. The methods for adding, editing, and deleting are exact copies of the EventController for the DataTables as well.

There are two unique methods here: the getEventPage() and the getAll(). The getEventPage() returns a JSP page containing a jQgrid table. The getAll() is a little-bit involved since it needs to wrap the results in a DTO, but nonetheless, it's quite straightforward.

We've also annotated the CRUD methods with two Java annotations: @Cacheable and @CacheEvict to add caching functionality. Notice how easy it is to add cache to our existing application.

To highlight the difference, I suggest comparing the DataTables and jQgrid version and monitor the calls to EventService via the Event Monitor page (part of the application's feature). Only the DataTables will show calls to readAll().

What is @Cacheable?
@Cacheable is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method. Source: Spring Reference 3.1.0.M1

What is @CacheEvict?
@CacheEvict demarcates methods that perform cache eviction, that is methods that act as triggers for removing data from the cache. Just like its sibling, @CacheEvict requires one to specify one (or multiple) caches that are affected by the action, allows a key or a condition to be specified but in addition, features an extra parameter allEntries which indicates whether a cache-wide eviction needs to be performed rather then just an entry one Source: Spring Reference 3.1.0.M1

3. JSP page

Now, let's examine the JSP page. It's a single page containing the following sections:
  1. URLs
  2. Imports
  3. Menu
  4. Table
  5. jQgrid initialization
  6. Pager functions
    1. Add function
    2. Edit function
    3. Delete function

event-page.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<c:url value="/" var="rootUrl"/>
<c:url value="/resources" var="resourcesUrl"/>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- CSS Imports-->
<link rel="stylesheet" type="text/css" media="screen" href="${resourcesUrl}/css/jquery/dark-hive/jquery-ui-1.8.6.custom.css"/>
<link rel="stylesheet" type="text/css" media="screen" href="${resourcesUrl}/css/jqgrid/ui.jqgrid.css"/>
<link rel="stylesheet" type="text/css" media="screen" href="${resourcesUrl}/css/main/main.css"/>
<!-- JS Imports -->
<script type="text/javascript" src="${resourcesUrl}/js/jquery/jquery-1.5.2.min.js"></script>
<script type="text/javascript" src="${resourcesUrl}/js/jquery/jquery-ui-1.8.12.custom.min.js"></script>
<script type="text/javascript" src="${resourcesUrl}/js/datejs/date.js"></script>
<script type="text/javascript" src="${resourcesUrl}/js/jqgrid/grid.locale-en.js" ></script>
<script type="text/javascript" src="${resourcesUrl}/js/jqgrid/jquery.jqGrid.min.js"></script>
<title>Events</title>
</head>
<body class="ui-widget-content">
<div id="menu">
<ul>
<li><a href="${rootUrl}event">Events (DataTables)</a></li>
<li><a href="${rootUrl}jqgrid/event">Events (jQgrid)</a></li>
<li><a href="${rootUrl}error">Errors</a></li>
<li><a href="${rootUrl}monitor/event">Monitor Events</a></li>
<li><a href="${rootUrl}monitor/error">Monitor Errors</a></li>
</ul>
<br style="clear:left"/>
</div>
<h3 class="title">Events - jQgrid Version</h3>
<div id="jqgrid">
<table id="grid"></table>
<div id="pager"></div>
</div>
<script type="text/javascript">
$(function() {
$("#grid").jqGrid({
url:'${rootUrl}jqgrid/event/getall',
datatype: 'json',
mtype: 'POST',
colNames:['Id',
'Name',
'Description',
'Participants',
'Date'],
colModel:[
{name:'id',index:'id', width:55, editable:false},
{name:'name',index:'name', width:90, editable:true},
{name:'description',index:'description', width:90, editable:true},
{name:'participants',index:'participants', editable:true},
{name:'date',index:'date', width:90, editable:false, formatter:'date', formatoptions:{newformat: 'd/M/Y'}, editable:true}
],
rowNum:10,
rowList:[10,20,30],
autowidth: true,
rownumbers: true,
pager: '#pager',
sortname: 'id',
viewrecords: true,
sortorder: "asc",
caption:"Events",
emptyrecords: "Empty records",
loadonce: false,
jsonReader : {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
cell: "cell",
id: "id"
}
});
$("#grid").jqGrid('navGrid','#pager',
{edit:false,add:false,del:false,search:true},
{ },
{ },
{ },
{
sopt:['eq', 'ne', 'lt', 'gt', 'cn', 'bw', 'ew'],
closeOnEscape: true,
multipleSearch: true,
closeAfterSearch: true }
);
$("#grid").navButtonAdd('#pager',
{ caption:"Add",
buttonicon:"ui-icon-plus",
onClickButton: addRow,
position: "last",
title:"",
cursor: "pointer"
}
);
$("#grid").navButtonAdd('#pager',
{ caption:"Edit",
buttonicon:"ui-icon-pencil",
onClickButton: editRow,
position: "last",
title:"",
cursor: "pointer"
}
);
$("#grid").navButtonAdd('#pager',
{ caption:"Delete",
buttonicon:"ui-icon-trash",
onClickButton: deleteRow,
position: "last",
title:"",
cursor: "pointer"
}
);
});
function addRow() {
// Get the currently selected row
$("#grid").jqGrid('editGridRow','new',
{ url: "${rootUrl}jqgrid/event/add",
serializeEditData: function(data){
data.id = 0;
data.date = new Date(data.date).toISOString();
return $.param(data);
},
recreateForm: true,
closeAfterAdd: true,
reloadAfterSubmit:true,
beforeShowForm: function(form) {
$("#date").datepicker({
changeMonth: true,
changeYear: true
});
},
afterSubmit : function(response, postdata)
{
var result = eval('(' + response.responseText + ')');
var errors = "";
if (result.success == false) {
for (var i = 0; i < result.message.length; i++) {
errors += result.message[i] + "<br/>";
}
} else {
$("#dialog").text('Entry has been added successfully');
$("#dialog").dialog(
{ title: 'Success',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
// only used for adding new records
var new_id = null;
return [result.success, errors, new_id];
}
});
}
function editRow() {
// Get the currently selected row
var row = $("#grid").jqGrid('getGridParam','selrow');
if( row != null )
$("#grid").jqGrid('editGridRow',row,
{ url: "${rootUrl}jqgrid/event/edit",
serializeEditData: function(data){
data.date = new Date(data.date).toISOString();
return $.param(data);
},
recreateForm: true,
closeAfterEdit: true,
reloadAfterSubmit:true,
beforeShowForm: function(form) {
$("#date").datepicker({
changeMonth: true,
changeYear: true
});
},
afterSubmit : function(response, postdata)
{
var result = eval('(' + response.responseText + ')');
var errors = "";
if (result.success == false) {
for (var i = 0; i < result.message.length; i++) {
errors += result.message[i] + "<br/>";
}
} else {
$("#dialog").text('Entry has been edited successfully');
$("#dialog").dialog(
{ title: 'Success',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
return [result.success, errors, null];
}
});
else alert("Please select row");
}
function deleteRow() {
// Get the currently selected row
var row = $("#grid").jqGrid('getGridParam','selrow');
// A pop-up dialog will appear to confirm the selected action
if( row != null )
$("#grid").jqGrid( 'delGridRow', row,
{ url: '${rootUrl}jqgrid/event/delete',
recreateForm: true,
beforeShowForm: function(form) {
//change title
$(".delmsg").replaceWith('<span style="white-space: pre;">' +
'Delete selected record?' + '</span>');
//hide arrows
$('#pData').hide();
$('#nData').hide();
},
reloadAfterSubmit:false,
closeAfterDelete: true,
afterSubmit : function(response, postdata)
{
var result = eval('(' + response.responseText + ')');
var errors = "";
if (result.success == false) {
for (var i = 0; i < result.message.length; i++) {
errors += result.message[i] + "<br/>";
}
} else {
$("#dialog").text('Entry has been deleted successfully');
$("#dialog").dialog(
{ title: 'Success',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
// only used for adding new records
var new_id = null;
return [result.success, errors, new_id];
}
});
else alert("Please select row");
}
</script>
<div id="dialog" title="Feature not supported" style="display:none">
<p>That feature is not supported.</p>
</div>
</body>
</html>
view raw event-page.jsp hosted with ❤ by GitHub


Let's discuss each section:

a. URLs
The following section declares two URLs which uses the JSTL core tag: the root and the resources URLs respectively. These URLs are here for reusability purposes:

<c:url value="/" var="rootUrl"/>
<c:url value="/resources" var="resourcesUrl"/>


b. Imports
The following snippet imports a number of CSS and JavaScript resources which includes the core jQuery library, the DateJS library (a Date utility, http://www.datejs.com/), and the jQgrid plugin (http://www.trirand.com/blog/):

<!-- CSS Imports-->
<link rel="stylesheet" type="text/css" media="screen" href="${resourcesUrl}/css/jquery/dark-hive/jquery-ui-1.8.6.custom.css"/>
<link rel="stylesheet" type="text/css" media="screen" href="${resourcesUrl}/css/jqgrid/ui.jqgrid.css"/>
<link rel="stylesheet" type="text/css" media="screen" href="${resourcesUrl}/css/main/main.css"/>
<!-- JS Imports -->
<script type="text/javascript" src="${resourcesUrl}/js/jquery/jquery-1.5.2.min.js"></script>
<script type="text/javascript" src="${resourcesUrl}/js/jquery/jquery-ui-1.8.12.custom.min.js"></script>
<script type="text/javascript" src="${resourcesUrl}/js/datejs/date.js"></script>
<script type="text/javascript" src="${resourcesUrl}/js/jqgrid/grid.locale-en.js" ></script>
<script type="text/javascript" src="${resourcesUrl}/js/jqgrid/jquery.jqGrid.min.js"></script>


c. Menu
The following section declares a menu list:

<div id="menu">
<ul>
<li><a href="${rootUrl}event">Events (DataTables)</a></li>
<li><a href="${rootUrl}jqgrid/event">Events (jQgrid)</a></li>
<li><a href="${rootUrl}error">Errors</a></li>
<li><a href="${rootUrl}monitor/event">Monitor Events</a></li>
<li><a href="${rootUrl}monitor/error">Monitor Errors</a></li>
</ul>
<br style="clear:left"/>
</div>


d. Table
The following section declares a div with two inner elements: a table and a div for attaching the jQgrid and the control buttons respectively:

<div id="jqgrid">
<table id="grid"></table>
<div id="pager"></div>
</div>


e. jQgrid initialization
The following section initializes the jQgrid table. The function declares the table properties, column models, url where to retrieve the data, and control buttons to display in the pager section:

$(function() {
$("#grid").jqGrid({
url:'${rootUrl}jqgrid/event/getall',
datatype: 'json',
mtype: 'POST',
colNames:['Id',
'Name',
'Description',
'Participants',
'Date'],
colModel:[
{name:'id',index:'id', width:55, editable:false},
{name:'name',index:'name', width:90, editable:true},
{name:'description',index:'description', width:90, editable:true},
{name:'participants',index:'participants', editable:true},
{name:'date',index:'date', width:90, editable:false, formatter:'date', formatoptions:{newformat: 'd/M/Y'}, editable:true}
],
rowNum:10,
rowList:[10,20,30],
autowidth: true,
rownumbers: true,
pager: '#pager',
sortname: 'id',
viewrecords: true,
sortorder: "asc",
caption:"Events",
emptyrecords: "Empty records",
loadonce: false,
jsonReader : {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
cell: "cell",
id: "id"
}
});
$("#grid").jqGrid('navGrid','#pager',
{edit:false,add:false,del:false,search:true},
{ },
{ },
{ },
{
sopt:['eq', 'ne', 'lt', 'gt', 'cn', 'bw', 'ew'],
closeOnEscape: true,
multipleSearch: true,
closeAfterSearch: true }
);
$("#grid").navButtonAdd('#pager',
{ caption:"Add",
buttonicon:"ui-icon-plus",
onClickButton: addRow,
position: "last",
title:"",
cursor: "pointer"
}
);
$("#grid").navButtonAdd('#pager',
{ caption:"Edit",
buttonicon:"ui-icon-pencil",
onClickButton: editRow,
position: "last",
title:"",
cursor: "pointer"
}
);
$("#grid").navButtonAdd('#pager',
{ caption:"Delete",
buttonicon:"ui-icon-trash",
onClickButton: deleteRow,
position: "last",
title:"",
cursor: "pointer"
}
);
});


f. Pager functions

1. Add function
The following section attaches a function to the Add button in the jQgrid pager section:

function addRow() {
// Get the currently selected row
$("#grid").jqGrid('editGridRow','new',
{ url: "${rootUrl}jqgrid/event/add",
serializeEditData: function(data){
data.id = 0;
data.date = new Date(data.date).toISOString();
return $.param(data);
},
recreateForm: true,
closeAfterAdd: true,
reloadAfterSubmit:true,
beforeShowForm: function(form) {
$("#date").datepicker({
changeMonth: true,
changeYear: true
});
},
afterSubmit : function(response, postdata)
{
var result = eval('(' + response.responseText + ')');
var errors = "";
if (result.success == false) {
for (var i = 0; i < result.message.length; i++) {
errors += result.message[i] + "<br/>";
}
} else {
$("#dialog").text('Entry has been added successfully');
$("#dialog").dialog(
{ title: 'Success',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
// only used for adding new records
var new_id = null;
return [result.success, errors, new_id];
}
});
}


2. Edit function
The following snippet attaches a function to the Edit button in the jQgrid pager section:

function editRow() {
// Get the currently selected row
var row = $("#grid").jqGrid('getGridParam','selrow');
if( row != null )
$("#grid").jqGrid('editGridRow',row,
{ url: "${rootUrl}jqgrid/event/edit",
serializeEditData: function(data){
data.date = new Date(data.date).toISOString();
return $.param(data);
},
recreateForm: true,
closeAfterEdit: true,
reloadAfterSubmit:true,
beforeShowForm: function(form) {
$("#date").datepicker({
changeMonth: true,
changeYear: true
});
},
afterSubmit : function(response, postdata)
{
var result = eval('(' + response.responseText + ')');
var errors = "";
if (result.success == false) {
for (var i = 0; i < result.message.length; i++) {
errors += result.message[i] + "<br/>";
}
} else {
$("#dialog").text('Entry has been edited successfully');
$("#dialog").dialog(
{ title: 'Success',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
return [result.success, errors, null];
}
});
else alert("Please select row");
}


3. Delete function
The following section attaches a function to the Delete button in the jQgrid pager section:

function deleteRow() {
// Get the currently selected row
var row = $("#grid").jqGrid('getGridParam','selrow');
// A pop-up dialog will appear to confirm the selected action
if( row != null )
$("#grid").jqGrid( 'delGridRow', row,
{ url: '${rootUrl}jqgrid/event/delete',
recreateForm: true,
beforeShowForm: function(form) {
//change title
$(".delmsg").replaceWith('<span style="white-space: pre;">' +
'Delete selected record?' + '</span>');
//hide arrows
$('#pData').hide();
$('#nData').hide();
},
reloadAfterSubmit:false,
closeAfterDelete: true,
afterSubmit : function(response, postdata)
{
var result = eval('(' + response.responseText + ')');
var errors = "";
if (result.success == false) {
for (var i = 0; i < result.message.length; i++) {
errors += result.message[i] + "<br/>";
}
} else {
$("#dialog").text('Entry has been deleted successfully');
$("#dialog").dialog(
{ title: 'Success',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
// only used for adding new records
var new_id = null;
return [result.success, errors, new_id];
}
});
else alert("Please select row");
}


Results

When we run the application, the result should be similar to the following image (this is an actual screenshot taken from a live deployment):


Limitations

Our jQgrid view has some limitations. However, these are not jQgrid limitations but rather something that we intentionally (and unintentionally) did not implement:
  • Search feature is not implemented
  • Sort feature is not implemented
  • UI validation is not fully implemented

Playground

Some developers might not have time to build the entire project. Maybe they just want something to play around really fast. Because of that, I've deployed live samples to Cloud Foundry and added sample fiddles via JSFiddle.

JSFiddle

If you want to explore more about jQgrid, I've provided a fiddle for you to play around. This fiddle do not need any server-side programs to run. Feel free to fork it.

Here's the fiddle: http://jsfiddle.net/krams/jqJch/

What is JSFiddle?
JsFiddle is a playground for web developers, a tool which may be used in many ways. One can use it as an online editor for snippets build from HTML, CSS and JavaScript. The code can then be shared with others, embedded on a blog, etc. Using this approach, JavaScript developers can very easily isolate bugs. We aim to support all actively developed frameworks - it helps with testing compatibility - Source: http://doc.jsfiddle.net/

Cloud Foundry

If you want to tinker with a live deployment, I suggest you visit the application's live site at http://spring-mysql-mongo-rabbit.cloudfoundry.com/jqgrid/event

What is Cloud Foundry?
Cloud Foundry is the open platform as a service project initiated by VMware. It can support multiple frameworks, multiple cloud providers, and multiple application services all on a cloud scale platform.

Next Section

In the next section, we will add messaging support using RabbitMQ and Spring AMQP. Read next.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC: Integrating MySQL, MongoDB, RabbitMQ, and AJAX - Part 1: jQgrid View ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

8 comments:

  1. Using the same code, but the submit on the add/edit pages doesn't seem to work. Any ideas ?

    ReplyDelete
  2. Trying this fiddle,

    http://jsfiddle.net/krams/jqJch/
    how do i view the data, the event jqgrid doesn't seem to be doing any formating also, add/edit doesn't work gives a status code 404.
    Can you help .

    ReplyDelete
  3. @smitha, it's supposed to produce a 404 since that fiddle is supposed to demo the jQgrid UI only without any server-side dependencies. Regarding your initial inquiry, you'll have to check the logs. It's hard to pinpoint the cause of such error if we don't have any logs.

    ReplyDelete
  4. Thanks for the wonderful tutorial. It has helped me a lot.. but i am stuck with some data type conversion for the date object.
    I defined an Entity with a date object
    @DateTimeFormat(iso=ISO.DATE)
    @Column private Date dob;
    and that resulted in json having the date as '710793000000' Hence i used the JsonSerializer http://blog.seyfi.net/2010/03/how-to-control-date-formatting-when.html
    and converted the date to the dd/mm/yy format. With this i am able to get the right date in the jqgrid. But on edit, (i use the datepicker with the dd/mm/yy format, i am able to see that the post data has the same date. I do serialize the postdata with
    serializeRowData: function(postdata){
    return { x01: JSON.stringify(postdata) };
    }
    but the date in my controller is all wrong, it seems to use the date given for month and the year also gets messed up.. Can you help.

    ReplyDelete
  5. Nice tutorial
    I do not want to implement an 'id' field. Instead what i have is a Project list and i want the id to be projectId which is the primary key field of Project Entity class.

    so in colModel {
    name : 'projectId',
    key : true,
    width : 100,
    sortable : false,
    editable : false,
    search : false
    }

    ant in the
    jsonReader : {
    root : "projects",
    page : "page",
    total : "total",
    records : "records",
    repeatitems : false,
    id : "projectId"
    }

    but this doesnt work. any valuable comments?

    ReplyDelete
  6. I have read your blog its very attractive and impressive. I like it your blog.

    Spring online training Spring online training Spring Hibernate online training Spring Hibernate online training Java online training

    spring training in chennai spring hibernate training in chennai

    ReplyDelete
  7. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.

    core java training in Electronic City

    Hibernate Training in electronic city

    spring training in electronic city

    java j2ee training in electronic city

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete