Using jQuery/jqGrid in Portlet with Ajax

By Ramazan Fırın, 11 November 2009 17:09

Portlet  is a java-technology-based web component desciribed in JSR 186.JSR 168 Portlet APIs and request processing is not suitable for Ajax. If we want to use ajax in a portlet, jQuery is one of the best choices. jQuery is an amazing JavaScript library that makes it easy to create wonderful web effects in just a few lines of code and it is a great library for developing AJAX based application. It has a lot of features for css manupilation, effects ,events etc. Best of it, it is very simple to use, and there are tons of tutorialsThere is also a jquery-portlet library for adding namespaces to JQuery for multiple portlets displayed on the same page. Also there are many plugins for jQuery. One of my favorite is the jqGrid for manipulating tables and data grids.

jqGrid

In this tutorial, I will use jqGrid to build a portlet with a master-detail table. Here is a brief summary of the steps:

  1. Create a new portlet class.
  2. Add the view and edit JSP files with jQuery library.
  3. Add Servlet for ajax requests
  4. Add Portlet.xml file

Have a look at the tutorial creating portlet class and adding portlet.xml to complete these steps. We will concentrate to adding view jsp and adding servlet for ajax request.

Add the view JSP

Create jsp file which name is view.jsp with portlet tags.

<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ page import="javax.portlet.PortletSession" %>
<%@ page session="false" %>
<portlet:defineObjects/>

<div id="<portlet:namespace/>_main">

<div id="<portlet:namespace/>_content"></div>
</div>

After that, add script and jss file for jQuery library after the <div id=”<portlet:namespace/>_main”> tag.

<pre><script src="<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/js/jquery.js") %>"  type="text/javascript" ></script>
<script src="<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/js/jquery.easing.js") %>"  type="text/javascript" ></script>
<script src="<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/js/jquery.portlet-1.0.js") %>"  type="text/javascript" ></script>
<script src="<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/js//js/jquery-ui.js") %>"  type="text/javascript" ></script>
<script src="<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/js/jquery.jqGrid.min.js") %>"  type="text/javascript" ></script>

<link href="<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/css/smoothness/jquery-ui-1.7.2.custom.css")%>" rel="stylesheet" type="text/css" media="screen" ></link>
<link href="<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/css/ui.jqgrid.css")%>" rel="stylesheet" type="text/css" media="screen" ></link>

 

Now add two table before <div id=”<portlet:namespace/>_content”> tag.We added two tables because we will use two jqGrid components. Id values of the tables will be used in jQuery components.

<table id="masterGrid" cellpadding="0" cellspacing="0"></table>
<table id="detailGrid"  cellpadding="0" cellspacing="0"></table>

 

Next we add the namespace that separates this portlet from the others. We use the functions available in the jqeury-portlet library for this. Without the portlet namespace, displaying multiple portlets that use jquery on the same page may cause problems. To do this Add jQuery function  after css description

<script type="text/javascript">
var MasterDetailPortlet = function(nameSpace) {
    var mThis = $.Portlet.call(this, nameSpace); // This extends your portlet object
    mThis.ready = function() {

};
return mThis;
};

jQuery.registerPortlet(new MasterDetailPortlet("<portlet:namespace />"));

</script>

 

Now we will add a servlet to serv data to jqGrids.jqGtrid accepts two data formats:json and xml.In this tutorial we use xml.Because there are some libraries to convert java classes to xml  easily like JAXB and XmlBeans. JAXB is a part of Java 6 and some portals don’t work with Java 6. So in this tutorial, we will use XmlBeans.  The following XSD file describes our simple model.

 

Employee.xsd


<pre><?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://turkcell.com/terminal/1.0/2009"
	elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema"
	xmlns:trm="http://turkcell.com/terminal/1.0/2009">
	<element name="employee" type="trm:EmployeeCatalog"></element>
	<complexType name="EmployeeCatalogType">
		<sequence>
			<element name="employeeId" type="float">
			</element>
			<element name="name" type="string"></element>
			<element name="surname" type="string"></element>
			<element name="division" type="string"></element>
			<element name="detail" type="trm:EmployeeProjectInformation"
				minOccurs="0" maxOccurs="unbounded"></element>
		</sequence>
	</complexType>

	<complexType name="EmployeeProjectInformation">
		<sequence>
			<element name="projectName" type="string"></element>
			<element name="startDate" type="date"></element>
			<element name="endDate" type="date"></element>
			<element name="projectStatus" type="string"></element>
		</sequence>
	</complexType>

	<complexType name="EmployeeCatalog">
		<sequence>
			<element name="employeeList" type="trm:EmployeeCatalogType"
				minOccurs="0" maxOccurs="unbounded"></element>
		</sequence>
	</complexType>
</schema>

Next, we will use XmlBeans to map XSD to Java objects. We can generate java classes from xsd file. The simple servlet gets the ID as a parameter, send data for the corresponding all employees. Master table calls this servlet with id parameter as null and gets the full list.

public class JQGridServlet extends HttpServlet{
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		PrintWriter out = response.getWriter ();
		String id=request.getParameter("id");
		if(id==null){
			EmployeeDocument document= EmployeeDAO.getInstance().getAllEmployeeDocument();
			out.println(getStringFromXml(document));
		}else{
			EmployeeCatalogType catalog=EmployeeDAO.getInstance().getEmployeeCAtalogById(id);
			out.println(getStringFromXml(catalog));
		}
	}

MASTER TABLE

Now, we can add jqGrid components. There will be two jqGrid. Id of the jqGrid ‘s are masterGrid and detailGrid.

Add these code in mThis.ready = function() for masterGrid jqGrid

$("#masterGrid").jqGrid({
    	   	url: '<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/JQGridServlet")%>',
    		datatype: "xml",
    	   	colNames:["EMPLOYEE ID","NAME", "SURNAME", "DIVISION"],
    	   	colModel:[
    	   		{name:"EMPLOYEE",index:"Author", width:120, xmlmap:"employeeId"},
    	   		{name:"NAME",index:"Title", width:180,xmlmap:"name"},
    	   		{name:"SURNAME",index:"Manufacturer", width:100, align:"right",xmlmap:"surname"},
    	   		{name:"DIVISION",index:"ProductGroup", width:130,xmlmap:"division"}
    	   	],
    		height:100,
    	   	rowNum:10,
    	   	rowList:[10,20,30],
    	       viewrecords: true,
   		loadonce: true,
   		xmlReader: {
    				root :"employee",
    				row: "employeeList",
    				repeatitems: false,
    				id: "employeeId"
    		},
    		caption: "Master Table",
    		onSelectRow: function(ids)
    		{
				$("#detailTable").setGridParam({ datatype: 'xml',url:'<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/JQGridServlet")%>?id='+ids}).trigger("reloadGrid");
				$("#detailTable").setCaption("DETAIL TABLE- SELECTED_ID=: "+ids)
			;
        	}
    	});

Let me explain the parameters:

$(“#masterGrid”):points to <table id=”masterGrid”>

url : url of data , in this example /JQGridServlet servlet

datatype:format of data

height :height of table

caption:caption of table

xmlReader :This is the most important tag.This is a sample xml data

<?xml version="1.0" encoding="UTF-8"?>
<employee xmlns="http://turkcell.com/terminal/1.0/2009" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://turkcell.com/terminal/1.0/2009 Employee.xsd ">
  <employeeList>
    <employeeId>0.0</employeeId>
    <name>name</name>
    <surname>surname</surname>
    <division>division</division>
    <detail>
      <projectName>projectName</projectName>
      <startDate>2001-01-01</startDate>
      <endDate>2001-01-01</endDate>
      <projectStatus>projectStatus</projectStatus>
    </detail>
  </employeeList>
</employee>

in xmlReader

root:root of xml data

row : information for particular row

id :id of the row,(will be used when row selected)

colNames : Column names

colModel :column attributes

xmlMap in colModel:attribute name in the xml

onSelectRow: select event.We will explain later.

DETAIL TABLE

Add these code in mThis.ready = function() for detailGrid jqGrid
$("#detailTable").jqGrid({
    	   	url: '<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/JQGridServlet")%>',
    		datatype: "xml",
    	   	colNames:["PROJECT NAME","STATUS", "START DATE", "END DATE"],
    	   	colModel:[
    	   		{name:"Author",index:"Author", width:120, xmlmap:"projectName"},
    	   		{name:"Title",index:"Title", width:180,xmlmap:"startDate"},
    	   		{name:"Price",index:"Manufacturer", width:100, align:"right",xmlmap:"endDate"},
    	   		{name:"DatePub",index:"ProductGroup", width:130,xmlmap:"projectStatus"}
    	   	],
    		height:100,
    	   	rowNum:10,
    	   	rowList:[10,20,30],
    	    viewrecords: true,
   		loadonce: true,
    		xmlReader: {
    				root :"xml-fragment",
    				row: "detail",
    				repeatitems: false,
    				id: "employeeId"
    		},
    		caption: "Detail Table",
    	});

Now, we have two jqGrid in page….

onSelect Event

Our purpose is, when we select a row in masterTable,we want to see detail of the selected record in detailTable table

We can do it by onSelectRow event in masterTable.

onSelectRow: function(ids)
    		{
				$("#detailTable").setGridParam({ datatype: 'xml',url:'<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/JQGridServlet")%>?id='+ids}).trigger("reloadGrid");
				$("#detailTable").setCaption("DETAIL TABLE- SELECTED_ID=: "+ids)
			;
        	}

Lets look at parameters:

onSelectRow:function(ids) : ids means is ‘id of the selected row’.Id of the row can be configured by id element in xmlReader.

$(“#detailTable”).setGridParam : This method is used for setting parameters of jqGrid.This example we set datatype and url.In fact, there is no need to set datatype. Because datatype is no changed.But in my environment,it doesnt work without datatype.When setting url, we add id parameter to the url.Thus, JQGridServlet can detect by id which element we want.So we can see selected element’s data in detailTable.

$(“#detailTable”).trigger(“reloadGrid”);Reload the data with new url.

$(“#detailTable”).setCaption(); Set caption with selected row’s id.

This is the screeenShot.

masterDetailGrid

Now you can deploy your portlet.But to see data, you can add it manually in JQGridServlet. if you want , you can use this util class

package com.eteration.util;

import java.util.Calendar;

import com.turkcell.terminal.x10.x2009.EmployeeCatalog;
import com.turkcell.terminal.x10.x2009.EmployeeCatalogType;
import com.turkcell.terminal.x10.x2009.EmployeeDocument;
import com.turkcell.terminal.x10.x2009.EmployeeProjectInformation;

public class EmployeeUtil {

	static EmployeeUtil instance;
	EmployeeDocument employeeDocument;

	public static EmployeeUtil getInstance() {
	      if(instance == null) {
	         instance = new EmployeeUtil();
	      }
	      return instance;
	}

	protected EmployeeUtil() {
		employeeDocument = EmployeeDocument.Factory.newInstance();
		EmployeeCatalog employeeCatalog=employeeDocument.addNewEmployee();

		EmployeeCatalogType ramazan= employeeCatalog.addNewEmployeeList();
		ramazan.setDivision("SOFTWARE");
		ramazan.setEmployeeId(1);
		ramazan.setName("Ramazan");
		ramazan.setSurname("FIRIN");

		EmployeeProjectInformation ramazanDetail1=ramazan.addNewDetail();
		ramazanDetail1.setProjectName("Turkcell");
		ramazanDetail1.setProjectStatus("PASSIVE");
		ramazanDetail1.setEndDate(Calendar.getInstance());
		ramazanDetail1.setStartDate(Calendar.getInstance());

		EmployeeCatalogType necati=employeeCatalog.addNewEmployeeList();
		necati.setDivision("SOFTWARE");
		necati.setEmployeeId(2);
		necati.setName("Necati");
		necati.setSurname("PEYNİRCİ");

		EmployeeProjectInformation necatiDetail1=necati.addNewDetail();
		necatiDetail1.setProjectName("Turkcell");
		necatiDetail1.setProjectStatus("PASSIVE");
		necatiDetail1.setEndDate(Calendar.getInstance());
		necatiDetail1.setStartDate(Calendar.getInstance());

		EmployeeProjectInformation necatiDetail2=necati.addNewDetail();
		necatiDetail2.setProjectName("AKBANK");
		necatiDetail2.setProjectStatus("PASSIVE");
		necatiDetail2.setEndDate(Calendar.getInstance());
		necatiDetail2.setStartDate(Calendar.getInstance());

		EmployeeProjectInformation necatiDetail3=necati.addNewDetail();
		necatiDetail3.setProjectName("TREDA");
		necatiDetail3.setProjectStatus("PASSIVE");
		necatiDetail3.setEndDate(Calendar.getInstance());
		necatiDetail3.setStartDate(Calendar.getInstance());

		EmployeeCatalogType betul=employeeCatalog.addNewEmployeeList();
		betul.setDivision("SOFTWARE");
		betul.setEmployeeId(3);
		betul.setName("Betul");
		betul.setSurname("UNUVAR");

		EmployeeProjectInformation information= betul.addNewDetail();
		information.setProjectName("Turkcell");
		information.setProjectStatus("ACTIVE");
		information.setEndDate(Calendar.getInstance());
		information.setStartDate(Calendar.getInstance());

		EmployeeProjectInformation informationAvea= betul.addNewDetail();
		informationAvea.setProjectName("AVEA");
		informationAvea.setProjectStatus("ACTIVE");
		informationAvea.setEndDate(Calendar.getInstance());
		informationAvea.setStartDate(Calendar.getInstance());
	}
	public EmployeeDocument getEmployeeDocument() {
		return employeeDocument;
	}

	public void setEmployeeDocument(EmployeeDocument employeeDocument) {
		this.employeeDocument = employeeDocument;
	}

	public EmployeeCatalogType getEmployeeCatalogById(String id){
		EmployeeCatalogType[] list= employeeDocument.getEmployee().getEmployeeListArray();
		for(int i=0;i<list.length;i++){
			EmployeeCatalogType temp=list[i];
			if(temp.getEmployeeId()==Float.parseFloat(id))
				return temp;
		}
		return null;
	}
}
Bookmark and Share
VN:F [1.9.3_1094]
Rating: 4.6/5 (7 votes cast)
VN:F [1.9.3_1094]
Rating: +4 (from 6 votes)
Using jQuery/jqGrid in Portlet with Ajax, 4.6 out of 5 based on 7 ratings

2 Responses to “Using jQuery/jqGrid in Portlet with Ajax”

  1. Hugo Hugo says:

    nice but… xml to send not a good idea… XmlBeans…nice tecnology but it would be easier with json
    FYI there are some frameworks (e.g: flexjson) that can serialize Java classes into Json Strings that you can send out to the ajax call back and it would be easier to work with from javascript…and when you made the ajax request…in normal ajax calls you send strings as request parameters…so:
    The point xml beans works and does is job but there are simpler soluctions for the same behaviour!! keep it simple my friend!!

    Like or Dislike: Thumb up 2 Thumb down 1

    VA:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.3_1094]
    Rating: -1 (from 1 vote)
  2. nobie nobie says:

    error with EmployeeDAO.getInstance().getAllEmployeeDocument();
    and getStringFromXml(document) ;
    understand how do you have these class

    Like or Dislike: Thumb up 0 Thumb down 0

    VA:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.3_1094]
    Rating: 0 (from 0 votes)

Leave a Reply

Spam Protection by WP-SpamFree