PDA

View Full Version : Changes required at Server side JSON for using Paging.



Rajat Sharma
28 Nov 2011, 1:18 AM
Hi
I am an Ext begginner. I have a simple grid which (after it's fair share of problems) is able to fetch data from server that sends a JSONArray.
Here are the code snippets:

Server Side: JSONArray Generation

public JSONArray getUserJSON(){
JSONArray userJSON = new JSONArray();
String[] userArray = getuserArray(); //s java String array that contains the user list
for(String val : userArray) {
JSONObject user = new JSONObject();
user.put("name", val);
userJSON.add(user);
}
return userJSON;
}


Client Side: Grid


var userStore = Ext.create('Ext.data.Store', {
model: 'User',
proxy: {
type: 'ajax',
url : 'ActionServlet?task=userList',
reader: {
type: 'json',
model: 'User'
}
}
});


Ext.create('Ext.grid.Panel', {
renderTo: Ext.getBody(),
store: userStore,
width: 400,
height: 800,
title: 'Users',
columns: [
{
text: 'Name',
width: 100,
sortable: true,
hideable: false,
dataIndex: 'name'
}
],
dockedItems: [{
xtype: 'pagingtoolbar',
store: userStore, // same store GridPanel is using
dock: 'bottom',
displayInfo: true
}]
});
//userStore.load();
userStore.load({
params: {
// specify params for the first page load if using paging
start: 0,
limit: 10
}
});
};


I have managed this code from Ext PagingToolbar example. Infact "dockeditem" and adding parameters in "store.load" are the only two changes i have done.
My grid is able to load data. But all 75 records come at once. When i click the "forward arrow button" from the paging toolbar, on page 2 also, the entire grid gets loaded again. Basically, i am not able to use paging.
Now, http://docs.sencha.com/ext-js/4-0/#!/api/Ext.toolbar.Paging clearly says that
Paging is typically handled on the server side. The client sends parameters to the server side, which the server needs to interpret and then respond with the appropriate data.
Can someone please help on:
1) is the problem with the server side format of the array? The current format of the array (verified using developer tools) is
[{"name":"glsextusr23"},{"name":"GLSEXTUSR36"},{"name":"XBBJVC0"},{"name":"XBBKBJC"}..........and son on...]
2) if yes, how to recode and what is the concept behind this. The format specifed at the Ext API site is

{ "success": true, "results": 2000, "rows": [ // ***Note:** this must be an Array { "id": 1, "name": "Bill", "occupation": "Gardener" }, { "id": 2, "name": "Ben", "occupation": "Horticulturalist" }, ... { "id": 25, "name": "Sue", "occupation": "Botanist" } ]}Do these two values i.e success and results, pertain to paging. My JSON sent is an Array where as the example shows an Object (which has an Array). Do I need to change mine ? Please guide.
Thanks

tvanzoelen
28 Nov 2011, 1:42 AM
Yes you must define a total property on your reader and set your data under a root



reader: {
type : 'json',
root : 'data', //or the property where your data is in the returned JSON
totalProperty : 'total', //mapping to the property where the total number of record is found
successProperty: 'success'
}


Only return the records from the server wich are requested within the start and limit params.

Rajat Sharma
28 Nov 2011, 2:10 AM
tvanzoelen

Thanks for attending to question once again.
The current code for reader works normally. Of course, this may be incomplete in certain ways.

reader: {
type: 'json',
model: 'User'
}

According to the API, totalProperty is Name of the property from which to retrieve the total number of records in the dataset. I have explicitly set it to 'total' but no use. Can you please elaborate on it's purpose. I also do not understand root property clearly.
This is the new reader after making suggested changes:

reader: {
type: 'json',
model: 'User',
totalProperty : 'total',
successProperty: 'success',
// is 'name' correct value for root property ? format of JSON is posted above
root: 'name'
}

However, no changes despite this in output. Complete grid loading on every page.

Rajat Sharma
28 Nov 2011, 2:14 AM
Only return the records from the server wich are requested within the start and limit params.

Do you mean I have to manually return only a given number of records from server. For example,

userStore.load({
params: {
// specify params for the first page load if using paging
start: 0,
limit: 10
}
});
So it is our task to make sure that only 10 records are returned at a time. All the sequencing of records at server side has to be taken care off. Do I understand you correctly ?

tvanzoelen
28 Nov 2011, 2:20 AM
You must define totalproperty and your root in the reader



{success: true, total: 75, data: [{"name":"glsextusr23"},{"name":"GLSEXTUSR36"},{"name":"XBBJVC0"},{"name":"XBBKBJC"}..........and son on...]}


Your data section must return that many records as the size your pagesize. Do not return 75 records at once but eg. 10 if your pagesize is ten.

tvanzoelen
28 Nov 2011, 2:20 AM
yes

Rajat Sharma
28 Nov 2011, 2:25 AM
I am clear about the second part. I will send only <pageSize> number of records.
However, regarding the JSON change at server side. Current format is a JSONArray:

[{"name":"glsextusr23"},{"name":"GLSEXTUSR36"},{"name":"XBBJVC0"},{"name":"XBBKBJC"}...]

The format suggested by you seems to be a JSONObject where the value of the 'data' property is my JSONArray. So I got to change the design, and return JSONObject instead of JSONArray. Hope I have got you correctly.

skirtle
28 Nov 2011, 2:32 AM
The store will send a request a little like this:


ActionServlet?task=userList&page=1&start=0&limit=10&...

Your server must read and interpret these parameters. limit gives the page size and start gives the index of the first result. The parameter page gives the page number. Obviously you don't need all 3 to work out which page to return, you should choose which combination of these parameters make most sense for you.

Responsibility for returning the correct results lies solely with the server. If 10 results are requested you must return no more than 10 results. If you return 100 results they will still be added to the store and appear in the grid. The store will not attempt to perform internal paging if you return too many results.

Let's consider a JSON response like this:


{
"count": 78,
"data": [
{"name": "Tom"},
...
]
}

Here the data array should contain 10 results. The value count specifies the total number of results. In this case that tells the store that there are 8 pages. To configure a reader to consume this data you would need:


{
...
root: 'data',
totalProperty: 'count'
}

Note that you can save yourself a bit of config if you call your total property total as that is the default.

As you have already mentioned, simply returning an array as your response cannot work as there is no way to pass the total number of results to the store.

tvanzoelen
28 Nov 2011, 2:34 AM
Yes you must return a JSON object, but that JSON object also contains a JSON array with your data, a Boolean property and an Int property with your totalcount.

So, It think you must start struggle again with that JSON thing server side :)

Mathias.Deshayes
28 Nov 2011, 2:38 AM
Yes you need to return a JSONObject which contains your JSONArray. For example for a pagesize equals to 3, the object should be something like :



{success: true, total: 75, data: [{"name":"glsextusr23"},{"name":"GLSEXTUSR36"},{"name":"XBBJVC0"}]}

The "total" property should return the real total number of users, not just the number of returned users. This total will be used by your grid to display the number of page.

Rajat Sharma
28 Nov 2011, 4:30 AM
Thanks for those very comprehensive solutions.
JSON returned from server is an object now in the suggested format.


{"success":true,"total":75,"data":[{"name":"testdev02"},{"name":"mobile03"},{"name":"glsextusr17"}.....]}

The server side code is sending 10 records. Actually it is sending the number of records after "interpreting the parameters start, limit". The test client for it at server side where I manually use start and limit values in range of 10 such as 0,10 or 10,20 (format is start, limit), works well and always prints 10 records JSON.

However, while hitting from client, the following happens.
1st request - grid: 10 records - server log values start 0, limit 10, page 1
next page click - grid: 25 records - server log values start: 25, limit:25, page 2
next page click - grid: 25 records - server log values start: 50, limit:25, page 3

Only in 1st loading of grid , are the configured values for start and limit used. Earlier I thought that the values may be getting distorted because may be I am returning more than 10 records but the testclient (where i explicitly give values in range of 10) is ok.

Where could the values be changing for start and limit. Any suggestions.

In all the cases, the bottom of paging toolbar shows something like

Page 1 (or 2 or 3) of 3 Displaying 25-50 of 75

It seems the grid is hell bent in showing the results in sets of 3. The server side code is correct as per my knowledge. Here is the interface:

public JSONObject getUserJSON(int startIndex,int limit)

It is correctly returning values between start and limit. But the values themselves are getting changed after intial load. As evident from checking logs.
Where I am i going wrong ? Anything wrongly configured in grid ?

Rajat Sharma
28 Nov 2011, 5:28 AM
Got it !

There is a pageSize config for Ext.data.Store, which unless explicitly set, defaults to (not surprisingly) 25. Overrode it explicitly and all seems well now.
The key then, to paging I guess is to know that the server sends request something like:


ActionServlet?task=userList&page=1&start=0&limit=10&...
This is an important detail and very helpful in returning appropriate (number) records from server. I feel it is missing from API docs. If anyone feels otherwise, please poit out.