PDA

View Full Version : Grid Paging not Working



sachintaware
19 Dec 2011, 1:27 AM
Hello
I am working on the ext js grid which displays a few records from the database using java at backend.
But the paging part of the grid does not work.The paging scrollbar has the next and previous buttons working.
But the content is displayed all at once i.e on a single page and on navigation only the page number changes on the scrollbar.
Here is the code for the grid.


Ext.onReady(function() {

var itemsPerPage = 20;

/***********************Tree panel***************************/

var treePan=Ext.create('Ext.tree.Panel', {
id:'candTree',
renderTo: 'tree',
title: 'Simple Tree',
width: 200,
height: 300,
useArrows:true,
frame: true,

root: {
text: 'Root',
expanded: true,

children: [
{
text: 'Candidates',
id:'CH1',
leaf: true
},
{
text: 'Clients',
id:'CH2',
leaf: true
}
]
}
});



/*Handling tree Events*/

treePan.getSelectionModel().on('select', function(selModel, record) {

if (record.get('leaf')) {
//Ext.getCmp('candGrid').layout.setActiveItem(record.getId() + '-panel');

if(record.getId()=='CH1')
{
//window.alert('THis is'+record.getId() +'-panel');
Ext.define('Company', {
extend: 'Ext.data.Model',
fields: [
{name:'uname',type: 'string'},
{name:'fname',type: 'string'},
{name:'lname',type: 'string'},
{name:'emailid',type: 'string'},
{name:'statename',type: 'string'}]
// {name:'cityname',type: 'string'},
// {name:'countryname',type: 'string'}]
});

var store_company = Ext.create('Ext.data.Store',{
model: 'Company',
pageSize:itemsPerPage,
proxy: {
type: 'ajax',
url: 'register',
actionMethods: {create: "POST", read: "POST", update: "POST", destroy: "POST"},
reader: {
type: 'json',
root: 'device',
totalProperty: 'totalCount',
success:'true'
},

}

});

var grid_company = Ext.create('Ext.grid.Panel', {
store: store_company,
remoteSort:false,
columns:[
{
text : 'User Name',
width : 120,
sortable : true,

dataIndex: 'uname'
},
{
text : 'Firstname',
width : 120,
sortable : true,
dataIndex: 'fname'
},
{
text : 'Lastname',
width : 110,
sortable : true,
dataIndex: 'lname'
},
{
text : 'Email',
width : 150,
sortable : true,
dataIndex: 'emailid'
},
{
text : 'State',
width : 100,
sortable : true,
dataIndex: 'statename'
}
/* {
text : 'City',
width : 150,
sortable : true,
dataIndex: 'cityname'
},
{
text : 'Country',
width : 150,
sortable : true,
dataIndex: 'countryname'
}*/
],

bbar: Ext.create('Ext.PagingToolbar', {
store: store_company,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display"
}),
id:'candGrid',
height: 300,
width: 902,
title: 'Company List',
region:'center',
renderTo: 'grid-company',
viewConfig: {
stripeRows: true
}
});

/*store_company.load({
params: {
start: 0,
limit: itemsPerPage
}
});*/

store_company.loadPage(1);
}

/*Second tree item value grid-Contains details of the users*/

}//If closed here

});

});


There might be some stupid mistake but whatever i have tried did not work.Any help would be appreciated.

Regards
Sach
www.optionsconsultancy.com

tobiu
19 Dec 2011, 1:36 AM
does your backend only send the needed amount of records back -> in your case 20?

sachintaware
19 Dec 2011, 1:43 AM
Hello tobiu,
Thanks for your prompt reply.

No it sends all the records at present they are 45 or so.
The paging scrollbar distributes them across three pages (as expected ).

But all are displayed at once instead when i click the next button.On button click nothing happens.

The Json response has the totalCount value correct.I am not getting what's the problem here.

Regards
Sach
www.optionsconsultancy.com

tobiu
19 Dec 2011, 1:49 AM
do not mix paging scrollbar (sounds like a buffered grid) and paging toolbar.

the important thing with your server response is, that you can return totoalCount:45, but only send back the number of records that are actually shown (in your case 20).

out of the box, the paging store only supports remote paging.
condor has written an ux for ext js 3 for this (search for localpaging), but i do not know if this has been ported to 4.

so i definitely recommend to adjust your backend to use the start & limit params.

sachintaware
19 Dec 2011, 1:57 AM
If I am getting it right,do I have to make changes to the query that fetches the records from database.

i.e add limit parameter to my query like this.


select * from register order by firstname limit 20


But this will get the first 20 records only.Please correct if i am wrong and needed correction at the Backend

Thanks
Sachin

tobiu
19 Dec 2011, 3:12 AM
for the first page this is ok. i would not write 20 as a number, using the param limit that is send from the client makes more sense in case you want to change the number of rows at some time.

depending on which database you use, there are syntax versions like limit start, amount.
like limit 20, 20 for the second page.

sachintaware
19 Dec 2011, 8:52 AM
Hello tobiu
I have not done anything like this before so can you point me to some examples??
These are two examples that I found one uses HTTP proxy and the other jsonp.
Does one have advantage over the other??Any particular conditions to use them?

http://superdit.com/2011/01/11/extjs-dataview-with-pagination/
http://docs.sencha.com/ext-js/4-0/#!/example/grid/paging.html

Regards
Sachin

tobiu
19 Dec 2011, 9:21 AM
jsonp is meant for x-domain-useage.

your problem is just to get your database queries correct and this is depending on the DB you use. I can just see that it is SQL, but nothing more. asuming it was mysql:
http://php.about.com/od/mysqlcommands/g/Limit_sql.htm

but this is definitely something you should just google.

sachintaware
19 Dec 2011, 10:14 AM
Thank you for the inputs!!

Yes,I do use mysql,but i will have to pass the limit parameters(start,limit) dynamically.Each time user clicks next button the result should immediately reflect.I want to do it the best possible way to avoid re-work.

I read something about Memory proxy for pagination and the links I had posted in the above posts which uses http proxy and jsonp.

Regards
Sachin

skirtle
19 Dec 2011, 11:57 AM
To reiterate what tobiu has said, the store will not enforce the page size. This must be done on the server.

The store's proxy will automatically add parameters to the request to signify the desired page. These parameters are called page, start and limit. It isn't necessary to use all three of the parameters provided, choose whichever combination works best for you. You must read these on the server and return the correct subset of the results. If you return the wrong results (for example, returning 45 results when it requested 20) then the store will contain the wrong results, it doesn't attempt to fix it.

On some occasions it does make sense to do paging locally in the browser. The standard memory proxy doesn't support paging, however the ExtJS distribution contains an example proxy that does:

examples/ux/data/PagingMemoryProxy.js

Note however that local paging is rarely a good idea. It incurs the penalty of loading all the results up front whilst still forcing the user to interact with paging. It only makes sense if there's a good reason not to show all the results to the user straight away.

sachintaware
19 Dec 2011, 10:48 PM
Hello
Thanks skirtle for your views

I have made changes to handle the ajax response in my backend i.e java.



if (start!=0 && limit!=0)
{
start = Integer.parseInt(request.getParameter("start"));
limit = Integer.parseInt(request.getParameter("limit"));
}
else {
start =0;
limit =20 ;
}



The response from ajax sends the start,limit and page parameters(when I check it in the firebug they are shown correctly)
I pass them to the query like this:


select * from register order by firstname LIMIT +start+,+limit ;


But I dont get any result on the grid.And nothing in the response in firebug.What am i missing?

Regards
Sachin

skirtle
19 Dec 2011, 11:37 PM
You need to add some logging on the server, or run it in a debugger. It appears that from an ExtJS perspective everything is working correctly.

My first concern would be this line:


if (start!=0 && limit!=0)

which seems to check the values before they are assigned.

sachintaware
19 Dec 2011, 11:51 PM
Hello
I am adding the entire servlet code.Also,when I print the values and check the response header in firebug it shows the parameter values.
Please go through and correct me.



package com.extjs;
import java.io.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import javax.servlet.RequestDispatcher;
import javax.sql.*;
import java.sql.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;


public class register extends HttpServlet{

Statement ps1 = null;
ResultSet rs1 = null;
//public PreparedStatement ps;
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException{

response.setContentType("application/json");
PrintWriter pw = response.getWriter();
/********Getting the Paging parameters*******/

int start=0;
int limit=0;

if (start!=0 && limit!=0)
{
start = Integer.parseInt(request.getParameter("start"));
limit = Integer.parseInt(request.getParameter("limit"));
}
else {
start =0;
limit =20 ;
}



/*************SQL Connection*****************/

System.out.println("MySQL Connect Example.");
Connection conn = null;
String url = "jdbc:mysql://localhost:3306/";
String dbName = "user_register";
String driver = "com.mysql.jdbc.Driver";
String userName = "root";
String password = "root";


try {
Class.forName(driver).newInstance();
conn = DriverManager.getConnection(url+dbName,userName,password);

String query1="select * from register order by firstname LIMIT +start+,+limit";
// ps.setInt(1,start);
// ps.setInt(2,limit);

ps1 = conn.prepareStatement(query1);
rs1 = ps1.executeQuery(query1);

/*********Convert the result n to a Json array*******/

int count = 0;
JSONArray jArray = new JSONArray();
while(rs1.next())
{
count++;
Integer id = rs1.getInt(1);
String uname = rs1.getString(2);
String fname = rs1.getString(4);
String lname = rs1.getString(5);
String emailid = rs1.getString(6);
String statename = rs1.getString(7);
String cityname = rs1.getString(8);
String countryname = rs1.getString(9);

JSONObject jobj = new JSONObject();

jobj.put("uname",uname);
jobj.put("fname",fname);
jobj.put("lname",lname);
jobj.put("emailid",emailid);
jobj.put("statename",statename);
jobj.put("cityname",cityname);
jobj.put("countryname",countryname);
jArray.add(jobj);
}

JSONObject jObjDevice = new JSONObject();
jObjDevice.put("success",true);
jObjDevice.put("totalCount",count);
jObjDevice.put("device", jArray);

JSONObject jObjDeviceList = new JSONObject();
jObjDeviceList.put("devicelist", jObjDevice );

pw.println(jObjDevice.toString());

conn.close();
// pw.println("Disconnected from database");
} catch (Exception e)
{
e.printStackTrace();
}
}
}



Js code:


Ext.onReady(function() {

var itemsPerPage = 20;

/***********************Tree panel***************************/

var treePan=Ext.create('Ext.tree.Panel', {
id:'candTree',
renderTo: 'tree',
title: 'Simple Tree',
width: 200,
height: 300,
useArrows:true,
frame: true,

root: {
text: 'Root',
expanded: true,

children: [
{
text: 'Candidates',
id:'CH1',
leaf: true
},
{
text: 'Clients',
id:'CH2',
leaf: true
}
]
}
});


/*Fuction added for pagination

var myDirectfn = function(opts, fn, proxy) {
var start = opts.start,
end = opts.page * opts.limit,
data = [];
if (end > myData.length) end = myData.length;
for (var i = start; i < end; i++)
data.push(myData[i]);
data.total = myData.length;
fn(0, {
status: true,
result: data
});
};
myDirectfn.directCfg = {
method: {}
};*/


/*Handling tree Events*/

treePan.getSelectionModel().on('select', function(selModel, record) {

if (record.get('leaf')) {
//Ext.getCmp('candGrid').layout.setActiveItem(record.getId() + '-panel');

if(record.getId()=='CH1')
{
//window.alert('THis is'+record.getId() +'-panel');
Ext.define('Company', {
extend: 'Ext.data.Model',
fields: [
{name:'uname',type: 'string'},
{name:'fname',type: 'string'},
{name:'lname',type: 'string'},
{name:'emailid',type: 'string'},
{name:'statename',type: 'string'}]
// {name:'cityname',type: 'string'},
// {name:'countryname',type: 'string'}]
});

var store_company = Ext.create('Ext.data.Store',{
model: 'Company',
remoteSort: true,
pageSize:itemsPerPage,

proxy: {
type: 'ajax',
url: 'register',
actionMethods: {create: "POST", read: "POST", update: "POST", destroy: "POST"},


reader: {
type: 'json',
root: 'device',
totalProperty: 'totalCount'
}
}

/* proxy: new Ext.data.HttpProxy({

url: 'register',
actionMethods: {create: "POST", read: "POST", update: "POST", destroy: "POST"}
}),

reader: new Ext.data.JsonReader({
type:'json',
root:'device',
totalProperty: 'totalCount',
}, [ 'uname', 'fname','lname','emailid','statename']
)*/




});



var grid_company = Ext.create('Ext.grid.Panel', {
store: store_company,
remoteSort:false,
columns:[
{
text : 'User Name',
width : 120,
sortable : true,

dataIndex: 'uname'
},
{
text : 'Firstname',
width : 120,
sortable : true,
dataIndex: 'fname'
},
{
text : 'Lastname',
width : 110,
sortable : true,
dataIndex: 'lname'
},
{
text : 'Email',
width : 150,
sortable : true,
dataIndex: 'emailid'
},
{
text : 'State',
width : 100,
sortable : true,
dataIndex: 'statename'
}
/* {
text : 'City',
width : 150,
sortable : true,
dataIndex: 'cityname'
},
{
text : 'Country',
width : 150,
sortable : true,
dataIndex: 'countryname'
}*/
],

bbar: Ext.create('Ext.PagingToolbar', {
store: store_company,
pageSize:20,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display"
}),
id:'candGrid',
height: 300,
width: 902,
title: 'Company List',
region:'center',
renderTo: 'grid-company',
viewConfig: {
stripeRows: true
}
});

store_company.load({
params: {
start: 0,
limit: itemsPerPage
}
});

//store_company.loadPage(1);
}


}//If closed here

});

});


Regards
Sachin

skirtle
20 Dec 2011, 12:33 AM
I feel we're a long way off topic for an ExtJS forum.

Are you using an IDE for your Java? I copied your code into IntelliJ IDEA and it lit up with warnings.


int start=0;
int limit=0;

if (start!=0 && limit!=0)

It'll never go into this code branch. You set them to 0 then check if they're non-zero, which they clearly aren't.


String query1="select * from register order by firstname LIMIT +start+,+limit";

This line doesn't actually substitute in the values.

You're class should not be in the package com.extjs, that isn't your domain.

Your code for querying the database is pretty scary. I assume that code is going to be massively refactored once you've got it working.

sachintaware
20 Dec 2011, 1:03 AM
Hello
That was a mistake,I should set them to the default values initially and not "0".
Actually,I am not that familiar with java frameworks say spring MVC and EXTJs,which I am trying to learn.
This is a part of POC and I am trying to get it done using the limited knowledge(Servlets basically).
I will have to surely refactor it later.I thought it was my proxy that may have some problems,hence posted it from extjs point of view.

Won't the concatenation work in the query???
Thank you very much for your inputs.

Regards
Sachin

skirtle
20 Dec 2011, 1:25 AM
What you've written is this:


String query1="select * from register order by firstname LIMIT +start+,+limit";

I have no idea what the correct SQL syntax is but as you aren't actually using the variables start and limit I assume you mean this:


String query1 = "select * from register order by firstname LIMIT " + start + "," + limit;

As I've already mentioned, a decent IDE would pick up on these mistakes (in this case it would report that the variables are assigned values that are never used).

sachintaware
20 Dec 2011, 1:33 AM
Yes,i am using a version of edit plus which is not as intelligent as eclipse or intelliJ.

And the query part worked as you said.But initially it shows only the first 20 records now.
How can write a callback to pass the request on click of the next button??

Thanks and Regards
Sachin

skirtle
20 Dec 2011, 2:16 AM
Clicking the Next button will automatically send the request for the next page.


That was a mistake,I should set them to the default values initially and not "0".

Changing them from 0 to some other default value won't fix the logic error. Whatever values you hardcode the if check will still be wrong. From this I can only deduce that you still aren't parsing the start & limit parameters properly.

sachintaware
20 Dec 2011, 3:32 AM
Hello Skirtle

I tried to do that using this example using php,but did not succeed.This is a standalone one which does not use a database.


$dir_thumbs = "img/thumbs/";

$images = array();
$d = dir($dir_thumbs);

$start = isset($_REQUEST['start']) ? $_REQUEST['start'] : 0;
$limit = isset($_REQUEST['limit']) ? $_REQUEST['limit'] : 5;

while($name = $d->read()){
if(!preg_match('/\.(jpg|gif|png)$/', $name)) continue;
$size = filesize($dir_thumbs.$name);
$lastmod = filemtime($dir_thumbs.$name)*1000;
$images[] = array(
'name' => $name,
'thumb_url' => $dir_thumbs.$name
);
}

$result = count($images);

if ($start == 0) {
$finish = $limit;
} else {
$finish = $start + $limit;
}

$fetch_images = array();
for ($i = $start; $i < $finish; $i++) {
$fetch_images[] = $images[$i];
}

$d->close();
$o = array('result' => $result, 'images' => $fetch_images);
echo json_encode($o);

I used similar logic but not working,I still see the empty grid.

Regards
Sach

sachintaware
20 Dec 2011, 10:55 PM
Hello Skirtle and tobiu!!!

Got it working.

Thank you for the valuable comments.Hope to get them for my next posts also.;)

Regards
Sachin