Peter Channon Peter Channon - 2 months ago 12
C# Question

Kendo Grid not binding data on any page after the first

I have a kendo grid on a my *.cshtml page with server side paging. The reason for the server side bind was to only pull the amount of records and not all the data at once. It binds the data to the first page and shows the correct number pages for the grid but when I go to any other page, besides one, the data does not display.

Page 1 and Page 2

.cshtml

@(Html.Kendo()
.Grid<Data.DTO.EmployeeDto>()
.Name("EmployeeGrid")
.Columns(cols =>
{
cols.Bound(emp => emp.Id).Title("ID").Hidden();
cols.Bound(emp => emp.EmployeeNumber).Title("Employee ID").Width(100);
cols.Bound(emp => emp.IsPayRunReady).Title("Status").Width(10).ClientTemplate("<span title='This employee is #= IsPayRunReady ? '': 'not '#payrun ready.' class='#= IsPayRunReady ? 'okICN-small' : 'alertICN-small'#'>#= IsPayRunReady ? '': 'Not' # #= IsPayRunReady ? 'P':'p'#ayrun ready</span>");
cols.Bound(emp => emp.FirstName).Title("First Name").Width(100);
cols.Bound(emp => emp.LastName).Title("Last Name").Width(100);
cols.Bound(emp => emp.DateOfBirth).Title("DOB").Format("{0:dd/MM/yyyy}").Width(100);
cols.Template(@<text></text>).ClientTemplate("<a href='" + Url.Action("EmployeeDetailEdit", "EmployeeDetail") + "/#=Id#'>Edit</a>").Width(50);
cols.Template(@<text></text>).ClientTemplate("<a href='" + Url.Action("EmployeeDetailRead", "EmployeeDetailRead") + "/#=Id#'>View</a>").Width(50);
cols.Template(@<text></text>).ClientTemplate("<a class='k-button xxx' tag='#=Id#'>Delete</a>").Width(50);
})
.Pageable(pageable => pageable.ButtonCount(5))
.Sortable(sortable => sortable.AllowUnsort(false))
.Filterable()
.Resizable(resize => resize.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.Navigatable()
.Events(evt => evt.DataBound("afterGridLoaded"))
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.PageSize(10)
.ServerOperation(true)
.Model(model => { model.Id(emp => emp.Id); })
.Read(read => read.Action("EmployeeListPerPage", "EmployeeDetail"))
)
)


.cs

public ActionResult EmployeeListPerPage([DataSourceRequest] DataSourceRequest request)
{
Dispose();
EmployeeListRequest empList = new EmployeeListRequest();
empList.PageNum = request.Page;
empList.PageSize = request.PageSize;
//empList.OrderBy = null; //request.Sorts.Any() ? "EmployeeNumber" : request.Sorts[0].Member;

var dataSource = _payrollService.GetEmployeeListPerPage(empList);
var model = new EmployeeListModel(dataSource);

DataSourceResult result = model.Employees.ToDataSourceResult(request);
result.Total = dataSource.Total;
return Json(result, JsonRequestBehavior.AllowGet);
}


There is no errors that are returned. I have notice that on the first binding the DataSourceResult is set but when you page it does not get set. Please see the below screenshot,

enter image description here

Could the browser be caching the EmployeeListResponse that is return to the var Model?

Any help would be greatly appreciated.

Answer

The problem is that the results are skipped according to page number, not once, but twice.

Suppose you're querying for the second page:

  • your EmployeeListRequest runs the query, selecting items 11-20

  • The method ToDataSourceResult takes these 10 items, then runs the filter over them. It selects items 11-20 of these 10 items, which results in no items.

Your solution is to set up EmployeeListRequest so it does not filter on pages. Allow it to fetch everything, then get ToDataSourceResult to do the filtering.

You might be tempted to let EmployeeListRequest filter on pages, and then get ToDataSourceResult filter on everything else. This won't work if it is combined with any other filtering. Suppose you also filtered on "LastName = 'Smith', and there were 12 employees with that last name. The EmployeeListRequest would get any 10 employees (not just 'Smith'), and then the ToDataSourceResult would apply the "LastName" filter on just these 10 items. You need to apply the column filtering BEFORE you do the paging.