PDA

View Full Version : Server side sorting with EXTJS, DWR, JAVA



Praveen Adivi
28 Oct 2010, 7:58 AM
Hi Guys, I am a newbie to EXTJS and I was wondering if there were any examples that could walk me through the process of enabling directional server side sorting using EXTJS, DWR and Java. Thank you guys in advance

winklerd
28 Oct 2010, 9:02 AM
Server-side sorting has nothing to do with Ext. If Java is your server-side technology, you'll need to do your sorting there. Look at the Collections class and its subclasses. If you have further questions, a Java forum might be better suited to your needs.

Praveen Adivi
28 Oct 2010, 9:14 AM
Hi I have a code written in Java that uses Collections.sort() with an appropriate comparator. However, the issue I am facing is that I am unable to figure out how to pass the name/id of the column I am trying to sort along with the direction of the sort to DWR/JAVA. (I know how to sort in java once I get these parameters). I was wondering if you could walk me through what goes in to get this working

winklerd
28 Oct 2010, 9:21 AM
I've never used DWR, but I'm assuming you'll need to add parameters to your AJAX request. ExtJS has built-in AJAX support. Here's how you'd do it there.

GET method:

var columnname = 'foo';
var sortorder = 'ascending';
Ext.Ajax.request({
url: '/url/goes/here?columnname=' + columnname + '&sortorder=' + sortorder,
success: function() {},
failure: function() {}
});


POST method:

var columnname = 'foo';
var sortorder = 'ascending';
Ext.Ajax.request({
url: '/url/goes/here',
params: {
columnname: columnname,
sortorder: sortorder
},
success: function() {},
failure: function() {}
});

Praveen Adivi
28 Oct 2010, 9:25 AM
Thanks winklerd. I was wondering if there is a way of know what column header was clicked on in a Grid for sorting.. and if there is a way I can link this sort to what I am passing to the back end java server

plalx
28 Oct 2010, 9:46 AM
Use remoteSort: true as a config option on the store. It will pass a sort param (column name) and a dir param (direction) as POST by default.

winklerd
28 Oct 2010, 9:53 AM
Ah, didn't realize this was in a Grid. Yeah, scarsick's response is your best bet.

Praveen Adivi
28 Oct 2010, 11:04 AM
thanks guys. I will give it a shot and see how it goes.

Praveen Adivi
28 Oct 2010, 11:52 AM
Hi guys, like I said I am using DWR between extjs and Java and I am using a DWR proxy to pass the data given to it the loading phase using a JSONreader . Please find a code excerpt where I make the call to the dwr function pasted below

searchByCatalogStore = new Ext.data.Store({
proxy: new Ext.ux.data.DwrProxy({
apiActionToHandlerMap : {
read : {
dwrFunction : ProductSearchCatalog.getCatalogSearchData,
getDwrArgsFunction : function(request) {

if(clk==true){
request.params.start=0;
clk=false;
}
var params = request.params;
return[cID,selectedNode,params.start,params.limit,params.sort , params.dir];
}
}
}
}),
reader: new Ext.data.JsonReader({
totalProperty:'totalRecords',
root : 'objectsToConvertToRecords',
fields : [
{name: 'strMatNo'},
{name: 'strMatDesc'},
{name: 'strCustPartNumber'},
{name: 'strCustPartDescrip'},
{name: 'strListPrice',type:'float'},
{name: 'chk'},
{name: 'strVOLTAGEC'},
{name: 'strHORSEPOWER'},
{name: 'strAMPS'},
{name: 'strHORSEPOWER_HD'},
{name: 'strAMPS_HD'},
{name: 'strENCLOSURE'},
{name: 'strPOWER'},
{name: 'retrunMsg'}

],
remoteSort:true
})
});

please find my java method signature below
public JsonReaderResponse<ProductSearchCatalogGridDao> getCatalogSearchData(
//HttpServletRequest request, HttpServletResponse response,
String custId,String selectedNode,String strt,String lmt, String sort, String dir)

{}

Also,
in this method I have the following code to sort
if(sort!=null)
{

Collections.sort(data, new ProductComparator());
}

The problem I am facing is that the store and dir objects/strings are becoming null even when sorting is requested. Hope you guys can look into the same.


The sort and dir parameters you guys mentioned turn up as undefined

darthwes
28 Oct 2010, 7:25 PM
Use the code brackets.

Listen to beforeload on the DWRProxy. It gets on argument, params, does that have your sort and dir properties on it?

sort and dir WILL NOT be passed until you try to sort...

plalx
29 Oct 2010, 5:14 AM
sort and dir WILL NOT be passed until you try to sort...

This is true unless you pass a sortInfo config option to your store, and I think you should since it allows you to define your default sorting params.

Praveen Adivi
29 Oct 2010, 6:01 AM
it does not show the sort and dir propertieseven when I try to sort it. in fact it does not go to the server at all for sorting.

plalx
29 Oct 2010, 6:05 AM
The remoteSort: true config option must be set on the store, not the reader.

Praveen Adivi
29 Oct 2010, 6:20 AM
thanks guys that worked for me.

Praveen Adivi
29 Oct 2010, 11:10 AM
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Student Data</title>
<link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-3.0.0/resources/css/ext-all.css" />
<script type="text/javascript" src="http://extjs.cachefly.net/ext-3.0.0/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="http://extjs.cachefly.net/ext-3.0.0/ext-all-debug.js"></script>

<!-- DWR Dependencies -->
<script type="text/javascript" src="dwr/interface/BasicReadExampleInterface.js"></script>
<script type="text/javascript" src="dwr/engine.js"></script>
<script type='text/javascript' src='/dwr/interface/StudentDataProducer.js'></script>
<script type='text/javascript' src='/BasicReadExample/dwr/interface/StudentDataProducer.js'></script>


<!-- Ext Extensions -->
<!-- Note: this file isn"t within the example web-app initially. You"ll need to copy it there, or change the path. -->
<script type="text/javascript" src="js/DwrProxy.js"></script>
<script type="text/javascript">
Ext.onReady(

function ()
{

function inspect(obj, maxLevels, level)
{
var str = '', type, msg;

// Start Input Validations
// Don't touch, we start iterating at level zero
if(level == null) level = 0;

// At least you want to show the first level
if(maxLevels == null) maxLevels = 1;
if(maxLevels < 1)
return '<font color="red">Error: Levels number must be > 0</font>';

// We start with a non null object
if(obj == null)
return '<font color="red">Error: Object <b>NULL</b></font>';
// End Input Validations

// Each Iteration must be indented
str += '<ul>';

// Start iterations for all objects in obj
for(property in obj)
{
try
{

type = typeof(obj[property]);
str += '<li>(' + type + ') ' + property +
( (obj[property]==null)?(': <b>null</b>'):('')) + '</li>';

// We keep iterating if this property is an Object, non null
// and we are inside the required number of levels
if((type == 'object') && (obj[property] != null) && (level+1 < maxLevels))
str += inspect(obj[property], maxLevels, level+1);
}
catch(err)
{

if(typeof(err) == 'string') msg = err;
else if(err.message) msg = err.message;
else if(err.description) msg = err.description;
else msg = 'Unknown';

str += '<li><font color="red">(Error) ' + property + ': ' + msg +'</font></li>';
}
}

// Close indent
str += '</ul>';

return str;
}
function myPopup() {
window.open( "http://www.google.com/" );
return true;
}
var p = new Ext.Panel({
title: 'My Panel',
collapsible:true,
renderTo: 'container',
width:400,
html: '<a href="#" onclick="javascript:function(){function poponload(){testwindow= window.open ("", "mywindow","location=1,status=1,scrollbars=1,width=100,height=100"); testwindow.moveTo(0,0); }}">here</a>'
});

var formPanel = new Ext.FormPanel({
title : 'Grid Controls',
width:375,
frame : true,
defaultType: 'textfield',
items : [{
fieldLabel : 'First Name',
name : 'firstName',
value : 'FNU'
}, {
fieldLabel : 'Last name',
name : 'lastName',
value : 'LNU'
}
],
buttons: [{
text: 'Refresh Grid',
handler : loadGrid
}]



});
formPanel.render('controls');

var storeUsingDwrProxy = new Ext.data.Store({
proxy: new Ext.ux.data.DwrProxy({
apiActionToHandlerMap : {
read : {
dwrFunction : StudentDataProducer.getStudentData,
getDwrArgsFunction : function(trans) {
var params=trans.params;
// Ext.MessageBox.alert('title', inspect(params,5,1) );
var sort='';
var dir='';
var limit=20;
var start=0;

if(params!=null)
{
if(params.limit!=undefined&&params.limit!=null)
{
limit=params.limit;
}
if(params.start!=undefined&&params.start!=null)
{
start=params.start;
}
if(params.dir!=undefined&&params.dir!=null)
{
dir=params.dir;
}
if(params.sort!=undefined&&params.sort!=null)
{
sort=params.sort;
}
}

return [
formPanel.getForm().findField('firstName').getValue(),
formPanel.getForm().findField('lastName').getValue(),
start,limit,sort , dir
];
}
}
}
}),
reader: new Ext.data.JsonReader({
totalProperty:'totalRecords',
root : 'objectsToConvertToRecords',
fields : [
{name: 'firstName'},
{name: 'lastName'},
{name:'id'}
]
}),
remoteSort: true
});

storeUsingDwrProxy.setDefaultSort('id', 'asc');
var grid = new Ext.grid.GridPanel({
store : storeUsingDwrProxy,
columns: [
{header: "First Name", width: 160, sortable: true, dataIndex: 'firstName'},
{header: "Last Name", width: 160, sortable: true, dataIndex: 'lastName'},
{header: "ID", width: 160, sortable: true, dataIndex: 'id'}
],
stripeRows: true,
height:350,
width:375,
title:'Student Grid',
frame : true,
loadMask : true,
bbar:new Ext.PagingToolbar({
pageSize:20,
store:storeUsingDwrProxy,
displayInfo:true,
displayMsg: '{0} - {1} of {2}'

})
});





function loadGrid(){ storeUsingDwrProxy.load(); grid.render('grid'); }






}
);



</script>
</head>
<body>
<div id="controls"></div>
<div id="grid"></div>
<div id="container"/>
</body>
</html>

Praveen Adivi
29 Oct 2010, 11:13 AM
example jsp code: <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Student Data</title>
<link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-3.0.0/resources/css/ext-all.css" />
<script type="text/javascript" src="http://extjs.cachefly.net/ext-3.0.0/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="http://extjs.cachefly.net/ext-3.0.0/ext-all-debug.js"></script>

<!-- DWR Dependencies -->
<script type="text/javascript" src="dwr/interface/BasicReadExampleInterface.js"></script>
<script type="text/javascript" src="dwr/engine.js"></script>
<script type='text/javascript' src='/dwr/interface/StudentDataProducer.js'></script>
<script type='text/javascript' src='/BasicReadExample/dwr/interface/StudentDataProducer.js'></script>


<!-- Ext Extensions -->
<!-- Note: this file isn"t within the example web-app initially. You"ll need to copy it there, or change the path. -->
<script type="text/javascript" src="js/DwrProxy.js"></script>
<script type="text/javascript">
Ext.onReady(

function ()
{

function inspect(obj, maxLevels, level)
{
var str = '', type, msg;

// Start Input Validations
// Don't touch, we start iterating at level zero
if(level == null) level = 0;

// At least you want to show the first level
if(maxLevels == null) maxLevels = 1;
if(maxLevels < 1)
return '<font color="red">Error: Levels number must be > 0</font>';

// We start with a non null object
if(obj == null)
return '<font color="red">Error: Object <b>NULL</b></font>';
// End Input Validations

// Each Iteration must be indented
str += '<ul>';

// Start iterations for all objects in obj
for(property in obj)
{
try
{

type = typeof(obj[property]);
str += '<li>(' + type + ') ' + property +
( (obj[property]==null)?(': <b>null</b>'):('')) + '</li>';

// We keep iterating if this property is an Object, non null
// and we are inside the required number of levels
if((type == 'object') && (obj[property] != null) && (level+1 < maxLevels))
str += inspect(obj[property], maxLevels, level+1);
}
catch(err)
{

if(typeof(err) == 'string') msg = err;
else if(err.message) msg = err.message;
else if(err.description) msg = err.description;
else msg = 'Unknown';

str += '<li><font color="red">(Error) ' + property + ': ' + msg +'</font></li>';
}
}

// Close indent
str += '</ul>';

return str;
}
function myPopup() {
window.open( "http://www.google.com/" );
return true;
}
var p = new Ext.Panel({
title: 'My Panel',
collapsible:true,
renderTo: 'container',
width:400,
html: '<a href="#" onclick="javascript:function(){function poponload(){testwindow= window.open ("", "mywindow","location=1,status=1,scrollbars=1,width=100,height=100"); testwindow.moveTo(0,0); }}">here</a>'
});

var formPanel = new Ext.FormPanel({
title : 'Grid Controls',
width:375,
frame : true,
defaultType: 'textfield',
items : [{
fieldLabel : 'First Name',
name : 'firstName',
value : 'FNU'
}, {
fieldLabel : 'Last name',
name : 'lastName',
value : 'LNU'
}
],
buttons: [{
text: 'Refresh Grid',
handler : loadGrid
}]



});
formPanel.render('controls');

var storeUsingDwrProxy = new Ext.data.Store({
proxy: new Ext.ux.data.DwrProxy({
apiActionToHandlerMap : {
read : {
dwrFunction : StudentDataProducer.getStudentData,
getDwrArgsFunction : function(trans) {
var params=trans.params;
// Ext.MessageBox.alert('title', inspect(params,5,1) );
var sort='';
var dir='';
var limit=20;
var start=0;

if(params!=null)
{
if(params.limit!=undefined&&params.limit!=null)
{
limit=params.limit;
}
if(params.start!=undefined&&params.start!=null)
{
start=params.start;
}
if(params.dir!=undefined&&params.dir!=null)
{
dir=params.dir;
}
if(params.sort!=undefined&&params.sort!=null)
{
sort=params.sort;
}
}

return [
formPanel.getForm().findField('firstName').getValue(),
formPanel.getForm().findField('lastName').getValue(),
start,limit,sort , dir
];
}
}
}
}),
reader: new Ext.data.JsonReader({
totalProperty:'totalRecords',
root : 'objectsToConvertToRecords',
fields : [
{name: 'firstName'},
{name: 'lastName'},
{name:'id'}
]
}),
remoteSort: true
});

storeUsingDwrProxy.setDefaultSort('id', 'asc');
var grid = new Ext.grid.GridPanel({
store : storeUsingDwrProxy,
columns: [
{header: "First Name", width: 160, sortable: true, dataIndex: 'firstName'},
{header: "Last Name", width: 160, sortable: true, dataIndex: 'lastName'},
{header: "ID", width: 160, sortable: true, dataIndex: 'id'}
],
stripeRows: true,
height:350,
width:375,
title:'Student Grid',
frame : true,
loadMask : true,
bbar:new Ext.PagingToolbar({
pageSize:20,
store:storeUsingDwrProxy,
displayInfo:true,
displayMsg: '{0} - {1} of {2}'

})
});





function loadGrid(){ storeUsingDwrProxy.load(); grid.render('grid'); }






}
);



</script>
</head>
<body>
<div id="controls"></div>
<div id="grid"></div>
<div id="container"/>
</body>
</html>

example Java code:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.directwebremoting.annotations.RemoteMethod;
import org.directwebremoting.annotations.RemoteProxy;

@RemoteProxy(name="StudentDataProducer")
public class StudentDataProducer {
@RemoteMethod
public JsonReaderResponse<Student> getStudentData(String firstName, String lastName ,int start, int limit, String sort, String dir) {
// Validate the input:
// Grab the first 10 characters of the baseString.

List<Student> students = new ArrayList<Student>(1);
// Create dummy objects.




for(int i=0,j=24;i<25;i++,j--)
{
students.add(new Student(i, firstName+i, lastName+j));
}




if(sort!=null&&sort.equalsIgnoreCase("lastName"))

{
Collections.sort(students, new StudentLastNameComparator());

if(dir!=null&&dir.equalsIgnoreCase("DESC"))
{
Collections.reverse(students);
}
}
if(sort!=null&&sort.equalsIgnoreCase("firstName"))

{
Collections.sort(students, new StudentFirstNameComparator());

if(dir!=null&&dir.equalsIgnoreCase("DESC"))
{
Collections.reverse(students);
}
}

if(sort!=null&&sort.equalsIgnoreCase("ID"))

{
Collections.sort(students, new StudentIDComparator());

if(dir!=null&&dir.equalsIgnoreCase("DESC"))
{
Collections.reverse(students);
}
}
if(limit==0)
{
limit= 20;

}

List<Student> newStudentList=new ArrayList<Student>();
for(int i=start;i<limit+start&&i<25;i++)
{
newStudentList.add(students.get(i));
}


return new JsonReaderResponse<Student>(newStudentList,students.size());
}


}

example DAO for DWR:
import org.directwebremoting.annotations.DataTransferObject;
import org.directwebremoting.annotations.RemoteMethod;
import org.directwebremoting.annotations.RemoteProperty;
import org.directwebremoting.convert.ObjectConverter;

@DataTransferObject(converter = ObjectConverter.class)
public class Student {
@RemoteProperty
public int id;

@RemoteMethod
public int getId() {
return id;
}
@RemoteMethod
public void setId(int id) {
this.id = id;
}
@RemoteMethod
public String getFirstName() {
return firstName;
}
@RemoteMethod
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@RemoteMethod
public String getLastName() {
return lastName;
}
@RemoteMethod
public void setLastName(String lastName) {
this.lastName = lastName;
}
@RemoteProperty
public String firstName;

@RemoteProperty
public String lastName;

public Student(int id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public Student() {}


}

example JSONReaderResponse code I have used
import java.util.List;

import org.directwebremoting.annotations.DataTransferObject;
import org.directwebremoting.annotations.RemoteProperty;
import org.directwebremoting.convert.ObjectConverter;

/**
* Creates a response that can be consumed by an Ext.data.JsonReader.
* The client-side Ext.data.JsonReader must have the "root" property set to "objectsToConvertToRecords".
* Note: Ext documentation often uses "rows" for this property, but "objectsToConvertToRecords" is more clear.
* Example Ext.data.JsonReader configuration:
* {
* root : 'objectsToConvertToRecords'
* }
* If the parameterized type has two properties "field1" and "field2", then when an instance of this class is read by the client,
* it will look like:
* {
* objectsToConvertToRecords : [
* {
* field1 : 'value',
* field2 : 'value',
* }, {
* field1 : 'value',
* field2 : 'value',
* }
* ],
* success : true
* }
* @param <T> Type of Objects that will be converted to Ext.data.Records by the client-side Ext.data.DataReader.
*/
@DataTransferObject(converter = ObjectConverter.class)
public class JsonReaderResponse<T> {

@RemoteProperty
public List<T> objectsToConvertToRecords;

/**
* @see Ext.data.JsonReader.successProperty
*/
@RemoteProperty
public boolean success;

@RemoteProperty
public int totalRecords;
/**
* Creates a {@link #success}ful JsonReaderResponse with the provided {@link #objectsToConvertToRecords}.
* @param objectsToConvertToRecords
*/
public JsonReaderResponse(List<T> objectsToConvertToRecords) {
this.objectsToConvertToRecords = objectsToConvertToRecords;
success = true;
}

public JsonReaderResponse(List<T> objectsToConvertToRecords,int totalRecords) {
this.objectsToConvertToRecords = objectsToConvertToRecords;
success = true;
this.totalRecords=totalRecords;
}
/**
* Creates an un{@link #success}ful JsonReaderResponse with null {@link #objectsToConvertToRecords}.
* This signals the case where the client established a connection with the server,
* but the server couldn't fulfill it (e.g., user doesn't have proper user credentials).
* @param objectsToConvertToRecords
*/
public JsonReaderResponse() {
this.objectsToConvertToRecords = null;
success = false;
}
}

plalx
3 Nov 2010, 10:22 AM
@Praveen Adivi, when posting code, you should wrap it in CODE tags (use the # button of editor) or PHP tags.

Praveen Adivi
3 Nov 2010, 10:28 AM
k will keep that in mind