Displaying grid data after switching to Server Side paging - grid

I am converting my application to use Server Side Paging with the Kendo Grid UI. Prior to switching serverPaging to true, I was properly displaying my grid contents, and paging on the client side. However, once I turned on the serverPaging, my data was no longer visible. I have checked the network call, and my data is returning (only 2 records of 8 total) as expected, but I am not seeing it in the grid.
Here is the grid construction:
$v.KendoGrid.makeGrid(gridName, {
columns: [
{ field: 'IdentifierCode', title: 'User Name' },
{ field: 'CompanyName', title: 'Company' },
{ field: 'Email', title: 'Email' }
],
dataSource: {
pageSize: 2,
schema: {
data: 'Data', // records are returned in the data section of the response
model: {
id: 'Id',
fields: {
IdentifierCode: { type: 'string' },
CompanyName: { type: 'string' },
Email: { type: 'string' }
}
},
total: 'Total' // total number of records are in the total section of the response
},
serverPaging: true,
transport: {
read: {
url: window.urlConfigs.root + "Security/UserAccount/PagedListing"
dataType: "json",
type: "GET"
}
}
},
editable: false,
filterable: true,
height: 464,
pageable: true,
scrollable: true,
sortable: true
});
Here is the MVC Controller method:
public ActionResult PagedListing(int pageSize, int skip)
{
var entities = ReadRepo.All();
var total = entities.Count();
var data = entities.Skip(skip).Take(pageSize).Select(MapEntityToViewModel).ToList();
return Json(new { Total = total, Data = data }, JsonRequestBehavior.AllowGet);
}
And here is the data I get back on the network call:
{"Total":8,"Data":[{"Id":"928f0bb2-608b-417b-bf6e-e5c58f85fec2","IdentifierCode":"admin","FirstName":"Administrator","MiddleName":"of","MiddleNameHuman":"of","LastName":"GasStream","DisplayName":"Administrator of GasStream","Email":"admin#example.com","IsExternal":false,"UserTypeHuman":"Internal","CompanyId":"75bb05a4-1ec2-4042-aeba-a229008aca9f","CompanyName":"Entessa Pipeline & Terminal, MLP","CompanyIdentifierCode":"SHA","Password":"wFg/a/NEU6WM8z4YZBUduitIDROfeFz/+Za6leAHnBE=","PasswordChanged":false,"ForceNewPasswordFlag":false,"Settings":[],"RoleGroups":[]},{"Id":"47c29025-cfa8-4447-9ab7-a229008ad088","IdentifierCode":"contractcarl","FirstName":"Carl","MiddleName":null,"MiddleNameHuman":"","LastName":"Smithers","DisplayName":"Carl Smithers","Email":"carl#entessa.com","IsExternal":false,"UserTypeHuman":"Internal","CompanyId":"75bb05a4-1ec2-4042-aeba-a229008aca9f","CompanyName":"Entessa Pipeline & Terminal, MLP","CompanyIdentifierCode":"SHA","Password":"IWdH+qDIOucNrre6V4AgI6Exm2Vq5qkIdXdsWfP6jn4=","PasswordChanged":false,"ForceNewPasswordFlag":false,"Settings":[],"RoleGroups":[]}]}
I suspect I have missed something small, but after looking at this and trying all sorts of possible work-arounds, I cannot see it, so I am asking for some help. I thought once I got the data to return small sets from the Server, things would get simpler.
Thanks in advance,
Drew

I ended up finding the answer. the $v.KendoGrid was a method that wrapped the kendoGrid call itself, and in there something was getting reset to not allow the data to be parsed properly when it came back from the server properly paged.
I have since re-worked the mess so I can establish the necessary parameters in the $v.KendoGrid call for just my type of grid.
Thanks for the help, and the eyes to catch the comma, Brett.
Drew

Related

Cannot Paginate using Kendo UI and Web API

I am a complete novice in KendoUI so this might seem like a noob question.
I am trying to implement server side pagination using KendoUI and Web API.
This is my script for generating the Kendo Grid
$(function () {
$("#grid").kendoGrid({
height: 400,
columns: [
"FirstName",
"LastName",
{ field: "Mobile", width: "150px" },
{ field: "Email", width: "150px" },
{ field: "LoginVerified", width: "150px" },
{ field: "DivisionName", width: "100px" }
],
pageable: true,
sortable: true,
filterable: true,
dataSource: {
serverPaging: true,
serverFiltering: true,
serverSorting: true,
pageSize: 10,
transport: {
read: "/api/Users/GetStaffsPaged"
}
}
});
});
And this is my Web API function
[HttpGet]
[ActionName("GetStaffsPaged")]
public IEnumerable<StaffsBasicInfo> GetStaffsPaged()
{
var take = string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["take"]) ? 1000 : Convert.ToInt32(HttpContext.Current.Request.QueryString["take"]);
var skip = string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["skip"]) ? 1000 : Convert.ToInt32(HttpContext.Current.Request.QueryString["skip"]);
StaffsBasicInfoBL staffsBL = new StaffsBasicInfoBL();
List<StaffsBasicInfo> staffs = staffsBL.getAllStaffsBasicInfo();
staffs = staffs.Skip(skip).Take(take).ToList();
return staffs;
}
When I run my code, the Grid is always showing the first 10 records, but my database has 2000+ records.
I have tried lots of tutorials to solve this, but I cannot do pagination.
http://www.telerik.com/blogs/the-facts-on-using-kendo-ui-with-asp-net-webapi
According to the above tutorial, my code should work.
I have also tried this tutorial, but I Visual Studio cannot resolve the DataSource class.
http://blog.falafel.com/server-paging-sorting-filtering-kendo-datasourcerequest/
Please help me implement pagination
You are not returning "total" number of items present so that Kendo could generate total/size number of items in the pagination area.
Try returning
var totalCount = staffs.Count();
staffs = staffs.Skip(skip).Take(take).ToList();
return new { data = staffs, total = totalCount};
And in JavaScript, define schema (code removed for brevity):
$("#grid").kendoGrid({
// code removed for brevity
dataSource: {
transport: {
read: {
url: "/api/Users/GetStaffsPaged"
}
},
schema: {
data: "data",
total: "total"
}
}
});
Thus said, the approach here, which pulls all data from database and doing the pagination on server side, defeats the actual purpose of having server side pagination. Pagination should happen in database and not at server side.

How can I set the total number of data items in my grid using a function?

I've tried various ways to set the total number of records in the Kendo-UI Web Grid, without success.
I'm kind of lost on where I spend the amount processed in ajax, already assigns the total value in the schema for 4 to see if it happens more paging did not work, just shows the two records and it shows that there are more pages.
If anyone could help me I would be very grateful!
...
transport: {
read: function (option) {
$.ajax({
url: '<?=$view->encode('ctrl.php?turma=lista_turma');?>',
data:{
skip: option.data.skip,
take: option.data.take,
pageSize: option.data.pageSize,
page: option.data.page,
sorting: JSON.stringify(option.data.sort),
filter: JSON.stringify(option.data.filter)
},
success: function (result) {
option.success(JSON.parse(result));
},
error: function (result) {
alert(result);
}
},
schema: {
data: 'data',
total: function (data) {
return 4;
},
/*total: function (result) {
alert('aqui');
result = result.d || result;
return 4;
},*/
model: { id: "id_turma" },
fields: {
id_turma: { validation: { required: true } },
nome_turma: { validation: { required: true } },
sigla_turma: { validation: { required: true, max:12 } }
}
}
},
pageable: true,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
batch: true,
pageSize: 2
});
I'm not sure what you're trying to do with all those "eval" statements in your code. This looks like you're overcomplicating things a lot.
If you do server-side paging, the total should be returned from the server since the client typically doesn't know how many more records there are. If your response contains a property "total", then this should work:
schema: {
total: "total" // total is returned in the "total" field of the response
}
or this, if you want to use a function:
schema: {
total: function(response) {
return response.total; // total is returned in the "total" field of the response
}
}
Both taken from the docs:
http://docs.kendoui.com/api/framework/datasource#configuration-schema.total
Here's a working example: http://jsfiddle.net/lhoeppner/y6KdK/

Grid content JSON conversion

I have a grid where user and add new rows as many as they want. After adding all the rows, they click the "Save" button. On Save button click, I want to send all the data entered by the user in JSON format to the server side code (i.e. a servlet in my case)
Below is the model and store definition:
Ext.define('Plant', {
extend: 'Ext.data.Model',
fields: [
// the 'name' below matches the tag name to read, except 'availDate'
// which is mapped to the tag 'availability'
{name: 'common', type: 'string'},
{name: 'botanical', type: 'string'},
{name: 'light'},
{name: 'price', type: 'float'},
// dates can be automatically converted by specifying dateFormat
{name: 'availDate', mapping: 'availability', type: 'date', dateFormat: 'm/d/Y'},
{name: 'indoor', type: 'bool'}
]
});
// create the Data Store
var store = Ext.create('Ext.data.Store', {
// destroy the store if the grid is destroyed
autoDestroy: true,
model: 'Plant'
});
On click of the save button, I am able to get the store like this:
{
text: 'Save',
handler : function(){
//Getting the store
var records = grid.getStore();
console.log(records.getCount());
Ext.Ajax.request({
url: '/CellEditing/CellEditingGridServlet',
method: 'POST',
jsonData: {
//How to assign the store here such that
//it is send in a JSON format to the server?
},
callback: function (options, success, response) {
}
});
}
But I don't know like how to convert the store content into JSON and send it in the jsonData of the ajax request.
I want the JSON data something like this in the server side:
{"plantDetails":
[
{
"common": Plant1,
"light": 'shady',
"price": 25.00,
"availDate": '05/05/2013',
"indoor": 'Yes'
},
{
"common": Plant2,
"light": 'most shady',
"price": 15.00,
"availDate": '12/09/2012',
"indoor": 'No'
},
]
}
Please let me know how to achieve this.
Regards,
Agreed with Neil, the right way to do this is through an editable store outfited with a proxy and a writer. See example here: http://docs.sencha.com/ext-js/4-1/#!/example/grid/cell-editing.html
Store
writer :
{
type : 'json',
allowSingle : true
}
Experiment with allowSingle as per your use case
In your controller
//if you want to set extra params
yourStore.getProxy().setExtraParam("anyParam",anyValue);
// sync the store
yourStore.sync({success : function() {
yourGrid.setLoading(false);
.. },
scope : this // within the scope of the controller
});
You should be creating the model with a new id ( you can ignore it at the server side and use your own key generation , but it lets extjs4 for its internal purposes know that a new record has been created).
creating a model instance
var r = Ext.create('yourModel', { id: idGen++, propA : valA , ... });
insert to grid
store.insert(0,r);
var editPlugin = grid.getPlugin(editPluginId);
editPlugin.startEdit(0,1);
Once you receive a response back the id's can be update to their true value.
in the Store
reader :
{
type : 'json',
root : 'yourdata',
successProperty : 'success',
idProperty : 'id'
}
If you were to use the same grid for handling and editing then you could use the write event or the appropriate event
for more advanced handling in the Store
listeners :
{
write : function(store,operation, eOpts)
{
var insertedData = Ext.decode(operation.response.responseText);
.. do something
}
}
I would recommend using the mvc architecture of Extjs4
This is what I tried and it seems to work:
var store = Ext.create('Ext.data.Store', {
// destroy the store if the grid is destroyed
autoDestroy: true,
model: 'Plant',
proxy: {
type: 'ajax',
url: '/CellEditing/CellEditingGridServlet',
writer: {
type: 'json',
root: 'plantDetails'
}
}
handler : function(){
grid.getStore().sync();
But I am getting an additional parameter in the JSON at the server side:
"id": null
I don't have this id set in my model then where is this coming from? Is there some way to set some values to it rather than having a default null value?

Return JSON data from WebAPI Controller

I want to return some JSON data from my WebAPI controller and I want the returned data to be like this.
{"rows":[{"id":1,"cell":["1","amila","amila","False"]},{"id":2,"cell":["2","rakhitha","rakhitha","False"]},{"id":3,"cell":["3","Chathura","Chathura","False"]},{"id":4,"cell":["4","Geethaga","Geethaga","False"]}]}
But when I use the below code,
return new System.Web.Mvc.JsonResult()
{
Data = jsonData,
JsonRequestBehavior = System.Web.Mvc.JsonRequestBehavior.AllowGet
};
the data is returned like this.
{"Data":{"rows":[{"id":1,"cell":["1","amila","amila","False"]},{"id":2,"cell":["2","rakhitha","rakhitha","False"]},{"id":3,"cell":["3","Chathura","Chathura","False"]},{"id":4,"cell":["4","Geethaga","Geethaga","False"]}]},"JsonRequestBehavior":0}
There is an additional JSON key as "Data". I dont want that parameter and as my implementation I cant remove this "Data" part after getting it to the client side. Because the data received from the server is directly used to fill a jqGrid. The code is below.
$("#Grid1").jqGrid({
url: 'api/matchingservicewebapi/GetUser',
datatype: 'json',
mtype: 'GET',
colNames: ['', 'Name', 'FullName', 'IsActive'],
colModel: [
{ name: 'Id', index: 'Id', width: 200 },
{ name: 'Name', index: 'Name', width: 300 },
{ name: 'FullName', index: 'FullName', width: 300 },
{ name: 'IsActive', index: 'IsActive', width: 300 }
],
rowNum: 10,
rowList: [10, 20, 30],
pager: '#pager',
sortname: 'Id',
viewrecoreds: true,
sortorder: "desc",
imgpath: 'Themes/images'
}).navGrid(pager, { edit: true, add: true, del: true, refresh: true, search: true });
How do I remove this "Data" part? Because when you have this "Data" key in the returned JSON, jqGrid is not capable of filling that data to the grid.
I am using WebAPI Controller to return this data. But I tried using MVC3 controller, then this "Data" key was not in the returned JSON and data filled to the grid successfully. But I want to use WebAPI Controller. Please help to solve this.
Thank you in advance.
JsonResult is an MVC concept. For Web API, your controller can simply return a CLR object and it will be serialized into JSON (assuming the client asks for JSON).
The result you're seeing is because the entire JsonResult object is getting serialized into JSON.
To get started with Web API, see: http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
(Or you could continue to use an MVC controller ... is there a particular reason that you wanted to use a Web API controller?)
Json.NET works well for me. Just return the JObject in the Web API
http://james.newtonking.com/projects/json/help/html/CreatingLINQtoJSON.htm
JObject o = JObject.FromObject(new
{
channel = new
{
title = "James Newton-King",
link = "http://james.newtonking.com",
description = "James Newton-King's blog.",
item =
from p in posts
orderby p.Title
select new
{
title = p.Title,
description = p.Description,
link = p.Link,
category = p.Categories
}
}
})
set jsonreader option in jqGrid. like
jQuery("#gridid").jqGrid({
...
jsonReader : {root:"Data"},
...
});
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_string
Use data.d instead of data in your code.
success: function(data){
//create jquery object from the response html
var response=$(data.d);
//Your binding logic here
}
You can return the data in jqgrid required format. If you don't want to create a separate class for this, use dynamic return type in apicontroller. See working example here.

ExtJS4 - Reconfiguring a grid in ASP.NET - JSON structure issue

One of ASP.NET's security features is proving to be a mountain to scale here - the "d" property addition when returning a JSON response appears to be confusing ExtJS when I attempt to reconfigure a gridpanel dynamically, causing it to fail when attempting to generate new column structure.
I followed this solution by nicholasnet:
http://www.sencha.com/forum/showthread.php?179861-Dynamic-grid-columns-store-fields
and it works beautifully, until the JSON payload is wrapped around the "d" property, e.g.
{"d":{
"metaData": {
"root": "data",
"fields": [{
"type": "int",
"name": "id",
"hidden": true,
"header": "id",
"groupable": false,
"dataIndex": "id"
}, ...omitted for brevity...]
},
"success": true,
"data": [{
"id": "1",
"controller": "Permissions",
"description": "Allow to see permission by roles",
"administrator": true,
"marketing": false
}]
}
}
I can't work out how to tell ExtJS to skirt around this problem. I've tried setting the "root" property of the AJAX reader to "d.data" but that results in the grid showing the correct number of rows but no data at all.
I've all the property descriptors required for column metadata ("name", "header", "dataIndex") in the JSON so I don't believe the JSON structure to be the cause. My main lead at the moment is that on the event handler:
store.on
({
'load' :
{
fn: function(store, records, success, operation, eOpts)
{
grid.reconfigure(store,store.proxy.reader.fields);
},
scope: this
}
}, this);
The fields in historyStore.proxy.reader.fields part is undefined when I pass the "d"-wrapped JSON. Anyone have any ideas on why this is or how to solve this issue?
edit: my Store/proxy
Ext.define('pr.store.Store-History', {
extend: 'Ext.data.Store',
model: 'pr.model.Model-History',
proxy: {
type: 'ajax',
url: '/data/history.json',
reader: {
type: 'json',
root: 'd'
}
}
});
Ext.define('pr.store.Store-History', {
extend: 'Ext.data.Store',
model: 'pr.model.Model-History',
proxy: {
type: 'ajax',
url: '/data/history.json',
reader: {
type: 'json',
root: 'data',
readRecords: function(data) {
//this has to be before the call to super because we use the meta data in the superclass readRecords
var rootNode = this.getRoot(data);
if (rootNode.metaData) {
this.onMetaChange(rootNode.metaData); // data used to update fields
}
/**
* #deprecated will be removed in Ext JS 5.0. This is just a copy of this.rawData - use that instead
* #property {Object} jsonData
*/
this.jsonData = rootNode;
return this.callParent([rootNode]); // data used to get root element and then get data from it
},
}
}
});
Update:
you are not getting fields in reader because the default code for getting fields from data doesn't handle your wrapped data, so you need to change 'readRecords' function to handle your custom data

Resources