I'm implementing an asp.net MVC application that includes a page with nested data Grid. Currently, I'm binding data using a single complex data object and it's loading data correctly.
But the problem is when inner grids have so much data it takes some time to get data from the database and make a data object for all the rows.
What I need to do is get and bind inner grid data when the user expands the selected row.
<div class="panel panel-default">
<div class="panel-body">
<div id="purchase-order-grid"></div>
</div>
</div>
$(document).ready(function () {
$("#purchase-order-grid").kendoGrid({
columns: [
{
field: "PurchaseOrderNumber",
title: "Purchase Order",
width: 80,
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" }
},
{
field: "Store",
title: "Store",
width: 100,
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" }
}
],
detailTemplate: '<div class="second-level-grid"></div>',
detailInit: function (e) {
e.detailRow.find(".second-level-grid").kendoGrid({
dataSource: e.data.Products,
columns: [
{
field: "PartNumber",
title: "Part",
width: 70
},
{
field: "Description",
title: "Description",
width: 150
}
]
})
},
dataSource: {
type: "json",
transport: {
read: {
url: "@Html.Raw(Url.Action("List", "PurchasingPurchaseOrder"))",
type: "POST",
dataType: "json",
data: additionalData
}
}
}
});
}
function additionalData() {
var data = {
StoreId: $('#@Html.IdFor(model => model.StoreId)').val()
};
addAntiForgeryToken(data);
return data;
}
[HttpPost]
public virtual IActionResult List(PurchaseOrderSearchModel model, DataSourceRequest command)
{
int totalCount = 0;
var purchaseOrder = _purchaseOrderService.GetPurchaseOrdersWithSearchOption(model, out totalCount, command.Page - 1, command.PageSize);
return Json(new DataSourceResult { Data = purchaseOrder, Total = totalCount });
}
I found a solution finally. Adding full code for future references.
<div class="panel panel-default">
<div class="panel-body">
<div id="purchase-order-grid"></div>
</div>
</div>
var expanded = {};
var grid, id;
$(document).ready(function () {
var element = $("#purchase-order-grid").kendoGrid({
dataSource: {
type: "json",
transport: {
read: {
url: "@Html.Raw(Url.Action("List", "PurchasingPurchaseOrder"))",
type: "POST",
dataType: "json",
data: additionalData
}
},
schema: {
data: "Data",
total: "Total",
errors: "Errors"
},
error: function (e) {
display_kendoui_grid_error(e);
// Cancel the changes
this.cancelChanges();
},
pageSize: @(defaultGridPageSize),
serverPaging: true,
serverFiltering: true,
serverSorting: true
},
sortable: true,
pageable: true,
detailInit: detailInit,
dataBound: function (e) {
grid = this;
grid.tbody.find("tr[role='row']").each(function () {
var id = grid.dataItem(this).PurchaseOrderNumber;
if (expanded.hasOwnProperty(id) && expanded[id]) {
grid.expandRow(this);
}
});
},
detailExpand: function (e) {
id = this.dataItem(e.masterRow).PurchaseOrderNumber;
expanded[id] = true;
},
detailCollapse: function (e) {
id = this.dataItem(e.masterRow).PurchaseOrderNumber;
expanded[id] = false;
},
columns: [
{
field: "Store",
title: "Store",
width: 100,
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" }
},
{
field: "POCreatedOn",
title: "PO Created On",
width: 100,
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" }
},
{
field: "SalesOrderTotal",
title: "Sales Order Total",
width: 80,
headerAttributes: { style: "text-align:right" },
attributes: { style: "text-align:right" }
},
{
field: "TotalPOCost",
title: "Total PO Cost (€)",
width: 100,
headerAttributes: { style: "text-align:right" },
attributes: { style: "text-align:right" }
},
{
field: "ShipmentStatus",
title: "Shipment Status",
width: 100,
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" }
},
{
field: "PaymentStatus",
title: "Payment Status",
width: 90,
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" }
}
]
});
});
function detailInit(e) {
$("<div/>").appendTo(e.detailCell).kendoGrid({
dataSource: {
type: "json",
transport: {
read: {
url: "@Html.Raw(Url.Action("GetPurchaseOrderByPurchaseOrderNumber", "PurchasingPurchaseOrder"))",
type: "POST",
dataType: "json",
data: nestedGridData(e.data.PurchaseOrderNumber)
}
},
schema: {
data: "Data",
total: "Total",
errors: "Errors"
},
serverPaging: true,
serverSorting: true,
serverFiltering: true,
pageSize: 5,
filter: { field: "PurchaseOrderNumber", operator: "eq", value: e.data.PurchaseOrderNumber }
},
scrollable: false,
sortable: true,
pageable: true,
columns: [
{
field: "Description",
title: "Description",
width: 150
},
{
field: "SalesOrderId",
title: "Order",
width: 80,
template:'#=formatSalesOrderIds(SalesOrderId)#',
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" }
},
{
field: "QuantityOrdered",
title: "Qty Order",
width: 70,
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" }
},
{
field: "QuantityDispatched",
title: "Qty Shipped",
width: 70,
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" }
}
]
});
}
function nestedGridData(purchaseOrderNumber) {
var data = {
GoDirectlyToPurchaseOrderId: purchaseOrderNumber
};
addAntiForgeryToken(data);
return data;
}
public class PurchasingPurchaseOrderController
{
[HttpPost]
public virtual IActionResult List(PurchaseOrderSearchModel model, DataSourceRequest command)
{
int totalCount = 0;
var purchaseOrder = GetPurchaseOrdersWithSearchOption(model, out totalCount, command.Page - 1, command.PageSize);
return Json(new DataSourceResult { Data = purchaseOrder, Total = totalCount
});
}
[HttpPost]
public virtual IActionResult GetPurchaseOrderByPurchaseOrderNumber(PurchaseOrderSearchModel model, DataSourceRequest command)
{
int totalCount = 0;
var products= GetPurchaseOrderByPurchaseOrderNumber(model, out totalCount, command.Page - 1, command.PageSize);
return Json(new DataSourceResult { Data = products, Total = totalCount });
}
}
public class DataSourceRequest
{
public DataSourceRequest()
{
this.Page = 1;
this.PageSize = 10;
}
public int Page { get; set; }
public int PageSize { get; set; }
public List<Sort> Sort { get; set; }
}