Saturday, January 28, 2012

Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 3)

Review

In the previous section, we have created the Java classes and discussed jqGrid's jsonReader format. In this section, we will focus on the presentation layer, in particular the HTML and JavaScript files.


Presentation Layer

To display our data without page-refresh and interactively, we will add AJAX and jqGrid, a jQuery plugin, to present tabular data.

What is jQuery?

jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript.

Source: http://jquery.com/

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.

Source: http://www.trirand.com/jqgridwiki/doku.php

Preview

We only have a single HTML file (users.jsp, a JSP to be exact) to perform all actions. This page contains our jqGrid table and buttons for interacting with the data.

Entry page

Source

At first glance, when you look at the JavaScript code, it is somewhat intimidating, but once you've familiarized with the jqGrid syntax, you'll find that it's actually simple. If you aren't familiary with jqGrid, please visit the jqGrid Official Wiki

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:url value="/users/records" var="recordsUrl"/>
<c:url value="/users/create" var="addUrl"/>
<c:url value="/users/update" var="editUrl"/>
<c:url value="/users/delete" var="deleteUrl"/>
<html>
<head>
<link rel="stylesheet" type="text/css" media="screen" href='<c:url value="/resources/css/jquery-ui/pepper-grinder/jquery-ui-1.8.16.custom.css"/>'/>
<link rel="stylesheet" type="text/css" media="screen" href='<c:url value="/resources/css/ui.jqgrid-4.3.1.css"/>'/>
<link rel="stylesheet" type="text/css" media="screen" href='<c:url value="/resources/css/style.css"/>'/>
<script type='text/javascript' src='<c:url value="/resources/js/jquery-1.6.4.min.js"/>'></script>
<script type='text/javascript' src='<c:url value="/resources/js/jquery-ui-1.8.16.custom.min.js"/>'></script>
<script type='text/javascript' src='<c:url value="/resources/js/grid.locale-en-4.3.1.js"/>'></script>
<script type='text/javascript' src='<c:url value="/resources/js/jquery.jqGrid.min.4.3.1.js"/>'></script>
<script type='text/javascript' src='<c:url value="/resources/js/custom.js"/>'></script>
<title>User Records</title>
<script type='text/javascript'>
$(function() {
$("#grid").jqGrid({
url:'${recordsUrl}',
datatype: 'json',
mtype: 'GET',
colNames:['Id', 'Username', 'Password', 'First Name', 'Last Name', 'Role'],
colModel:[
{name:'id',index:'id', width:55, editable:false, editoptions:{readonly:true, size:10}, hidden:true},
{name:'username',index:'username', width:100, editable:true, editrules:{required:true}, editoptions:{size:10}},
{name:'password',index:'password', width:100, editable:true, editrules:{required:true}, editoptions:{size:10}, edittype:'password', hidden:true},
{name:'firstName',index:'firstName', width:100, editable:true, editrules:{required:true}, editoptions:{size:10}},
{name:'lastName',index:'lastName', width:100, editable:true, editrules:{required:true}, editoptions:{size:10}},
{name:'role',index:'role', width:50, editable:true, editrules:{required:true},
edittype:"select", formatter:'select', stype: 'select',
editoptions:{value:"1:Admin;2:Regular"},
formatoptions:{value:"1:Admin;2:Regular"},
searchoptions: {sopt:['eq'], value:":;1:Admin;2:Regular"}}
],
postData: {},
rowNum:10,
rowList:[10,20,40,60],
height: 240,
autowidth: true,
rownumbers: true,
pager: '#pager',
sortname: 'id',
viewrecords: true,
sortorder: "asc",
caption:"Records",
emptyrecords: "Empty records",
loadonce: false,
loadComplete: function() {},
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},
{}, {}, {},
{ // search
sopt:['cn', 'eq', 'ne', 'lt', 'gt', '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"
}
);
// Toolbar Search
$("#grid").jqGrid('filterToolbar',{stringResult: true,searchOnEnter : true, defaultSearch:"cn"});
});
function addRow() {
$("#grid").jqGrid('setColProp', 'username', {editoptions:{readonly:false, size:10}});
$("#grid").jqGrid('setColProp', 'password', {hidden: false});
$("#grid").jqGrid('setColProp', 'password', {editrules:{required:true}});
// Get the currently selected row
$('#grid').jqGrid('editGridRow','new',
{ url: '${addUrl}',
editData: {},
serializeEditData: function(data){
data.id = 0;
return $.param(data);
},
recreateForm: true,
beforeShowForm: function(form) {
$('#pData').hide();
$('#nData').hide();
$('#password',form).addClass('ui-widget-content').addClass('ui-corner-all');
},
beforeInitData: function(form) {},
closeAfterAdd: true,
reloadAfterSubmit: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 {
$('#msgbox').text('Entry has been added successfully');
$('#msgbox').dialog(
{ title: 'Success',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
// only used for adding new records
var newId = null;
return [result.success, errors, newId];
}
});
$("#grid").jqGrid('setColProp', 'password', {hidden: true});
} // end of addRow
function editRow() {
$("#grid").jqGrid('setColProp', 'username', {editoptions:{readonly:true, size:10}});
$("#grid").jqGrid('setColProp', 'password', {hidden: true});
$("#grid").jqGrid('setColProp', 'password', {editrules:{required:false}});
// Get the currently selected row
var row = $('#grid').jqGrid('getGridParam','selrow');
if( row != null ) {
$('#grid').jqGrid('editGridRow', row,
{ url: '${editUrl}',
editData: {},
recreateForm: true,
beforeShowForm: function(form) {
$('#pData').hide();
$('#nData').hide();
},
beforeInitData: function(form) {},
closeAfterEdit: true,
reloadAfterSubmit: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 {
$('#msgbox').text('Entry has been edited successfully');
$('#msgbox').dialog(
{ title: 'Success',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
// only used for adding new records
var newId = null;
return [result.success, errors, newId];
}
});
} else {
$('#msgbox').text('You must select a record first!');
$('#msgbox').dialog(
{ title: 'Error',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
}
function deleteRow(obj, args) {
// 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:'${deleteUrl}',
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:true,
closeAfterDelete: true,
serializeDelData: function (postdata) {
var rowdata = $('#grid').getRowData(postdata.id);
// append postdata with any information
return {id: postdata.id, oper: postdata.oper, username: rowdata.username};
},
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 {
$('#msgbox').text('Entry has been deleted successfully');
$('#msgbox').dialog(
{ title: 'Success',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
// only used for adding new records
var newId = null;
return [result.success, errors, newId];
}
});
else {
$('#msgbox').text('You must select a record first!');
$('#msgbox').dialog(
{ title: 'Error',
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
}
</script>
</head>
<body>
<h1 id='banner'>System Records</h1>
<div id='jqgrid'>
<table id='grid'></table>
<div id='pager'></div>
</div>
<div id='msgbox' title='' style='display:none'></div>
</body>
</html>
view raw users.jsp hosted with ❤ by GitHub

You might be asking: "What's that humongous lines of jibberish code?" If you'd been following my blog, you would notice that I have tackled jqGrid a couple of times from my previous tutorials. If my explanation in this tutorial isn't enough, please see the following tutorials for an alternative perspective:


An In-depth Look

If we partition this HTML page, you will notice the following sections:
  • URL imports
    <c:url value="/users/records" var="recordsUrl"/>
    <c:url value="/users/create" var="addUrl"/>
    <c:url value="/users/update" var="editUrl"/>
    <c:url value="/users/delete" var="deleteUrl"/>
    view raw users.jsp hosted with ❤ by GitHub
  • JavaScript and CSS imports
    <link rel="stylesheet" type="text/css" media="screen" href='<c:url value="/resources/css/jquery-ui/pepper-grinder/jquery-ui-1.8.16.custom.css"/>'/>
    <link rel="stylesheet" type="text/css" media="screen" href='<c:url value="/resources/css/ui.jqgrid-4.3.1.css"/>'/>
    <link rel="stylesheet" type="text/css" media="screen" href='<c:url value="/resources/css/style.css"/>'/>
    <script type='text/javascript' src='<c:url value="/resources/js/jquery-1.6.4.min.js"/>'></script>
    <script type='text/javascript' src='<c:url value="/resources/js/jquery-ui-1.8.16.custom.min.js"/>'></script>
    <script type='text/javascript' src='<c:url value="/resources/js/grid.locale-en-4.3.1.js"/>'></script>
    <script type='text/javascript' src='<c:url value="/resources/js/jquery.jqGrid.min.4.3.1.js"/>'></script>
    <script type='text/javascript' src='<c:url value="/resources/js/custom.js"/>'></script>
    view raw users.jsp hosted with ❤ by GitHub
  • jqGrid initialization
    <script type='text/javascript'>
    $(function() {
    $("#grid").jqGrid({
    ....
    });
    $("#grid").jqGrid('navGrid','#pager',
    ...
    );
    $("#grid").navButtonAdd('#pager',
    ...
    );
    $("#grid").navButtonAdd('#pager',
    ...
    );
    $("#grid").navButtonAdd('#pager',
    ...
    );
    // Toolbar Search
    $("#grid").jqGrid('filterToolbar',{stringResult: true,searchOnEnter : true, defaultSearch:"cn"});
    });
    ...
    </script>
    view raw users.jsp hosted with ❤ by GitHub
  • JavaScript functions: addRow(), editRow(), deleteRow()
    <script type='text/javascript'>
    ...
    function addRow() {
    ...
    }
    function editRow() {
    ...
    }
    function deleteRow() {
    ...
    }
    </script>
    view raw users.jsp hosted with ❤ by GitHub
  • HTML table
    <div id='jqgrid'>
    <table id='grid'></table>
    <div id='pager'></div>
    </div>
    view raw users.jsp hosted with ❤ by GitHub

Notice how we've separated the HTML markup from the JavaScript code. We could, of course, move that one huge JavaScript code in an external js file, and make the HTML look somewhat smaller. But I'll leave that exercise to my readers.

Next

In the next section, we will focus on the configuration files for enabling Spring MVC. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide (Part 3) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

10 comments:

  1. Thank you very much - it was helpful for me :-)

    ReplyDelete
  2. Dear Krams

    I have deployed this project on cloudfoundry , but when I access the url http://hamidspringjqrid.cloudfoundry.com/krams/crud it does not show the jqgid on the page instead show the plain json with i.e
    {"total":"10","page":"1","records":"3","rows":[{"id":1,"firstName":"John","lastName":"Smith"},{"id":2,"firstName":"Jane","lastName":"Adams"},{"id":3,"firstName":"Jeff","lastName":"Mayer"}]}

    So please help
    Thank you

    ReplyDelete
  3. Have you tried deploying this on your local machine first? Did you get the same results?

    ReplyDelete
  4. Dear Krams

    Yes , I have tried on localhost , it works fine , no problem , problem in deploying the project on the remote server http://hamidspringjqrid.cloudfoundry.com/krams/crud

    So please help
    Lot of thanks

    ReplyDelete
  5. krams: have you run into the bug with delete?

    http://www.trirand.com/jqgridwiki/doku.php?id=wiki:form_editing

    It looks like there could be an issue with an improper JS call to the "split" function on an array.

    Error message when using form editing to do a delete is:

    "Uncaught TypeError: Object 1 has no method 'split'"

    Ever run into this?

    ReplyDelete
  6. @Anonymous, I have not encountered that so far. What version of jQuery and jqGrid are you using?

    ReplyDelete
  7. jqGrid 4.3.1 and jQuery 1.7.1.

    It's still entirely possible (nay, likely) I'm doing something stupid, but I found it interesting to see other similar findings in the comments on the above link.

    ReplyDelete
  8. Krams, nice tutorial and I got it to run on my local machine under eclipse easily. However, I when I copied your jqgrid directories (js and css) to a new project, eclipse showed syntax errors in the jquery-1.6.4.min.js file - which it is not doing in your project! How did you set your project that this is not happening? Also, I notice this doesn't happen with your older jqgrid tutorial. Apparently the eclipse parser is out of date, but that doesn't explain why this project doesn't show errors.

    Thanks
    Dave

    ReplyDelete
  9. 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
  10. Great Content. It will useful for knowledge seekers. Keep sharing your knowledge through this kind of article.
    MVC Training in Chennai
    MVC Classes in Chennai

    ReplyDelete