I am using the Kendo UI Grid and currently display parent child records appropriately. However, it turns out that i will actually need to display n-levels vs. strictly parent-child. Not every record will have children, but some will have multiple levels.
Current grid code:
var jgrid = $("#boxesgrid").kendoGrid({
columns: [
{
field: "JobId",
hidden: true
},
{
field: "PercentComplete",
hidden: true
},
{
field: "JobStatusId",
hidden: true
},
{
field: "AppName",
title: "App",
template: "<span>${AppName}</span><img class='health-img-r' id=app-${JobId} title='health' src='' alt='health_png' />",
width: "5%",
editable: false,
sortable: false
},
{
field: "JobName",
title: "Box Name",
width: "17%",
filterable: false
},
{
field: "StartTime",
title: "Start Time",
width: "14%",
filterable: false
},
{
field: "EndTime",
title: "End Time",
width: "14%",
filterable: false
},
{
field: "JobStatusId",
title: "Status",
template: "<img class='health-img-l' id=app-${JobId} title='health' src='' alt='health_png' /><span>${JobStatus}</span>",
editable: false,
filterable: false
}
],
sortable: {
mode: "single",
allowUnsort: true
},
pageable: {
pageSizes: [50],
numeric: true,
refresh: true,
pageSize: 50
},
autoBind: false,
scrollable: false,
resizable: true,
detailInit: detailInit,
dataSource: boxesDataSource,
dataBound: function () {
var grid = this;
grid.tbody.find(">tr").each(function () {
var row = $(this).closest("tr");
var model = grid.dataItem(row);
var img = $(this).find("img");
if (model.JobStatusId == 4 && model.PercentComplete < 100) {
img.attr("src", function() {
return imgSrc + imgGreen;
});
} else if (model.JobStatusId == 4) {
img.attr("src", function() {
return imgSrc + imgAmber;
});
} else if (model.JobStatusId == 7) {
img.attr("src", function() {
return imgSrc + imgIce;
});
} else if (model.JobStatusId == 8) {
img.attr("src", function() {
return imgSrc + imgHold;
});
} else if (model.JobStatusId == 5) {
img.attr("src", function() {
return imgSrc + imgBlue;
});
} else {
img.attr("src", function() {
return imgSrc + imgRed;
});
}
});
}
}).data("kendoGrid");
Current child grid:
function detailInit(e) {
$("<div/>").appendTo(e.detailCell).kendoGrid({
dataSource: {
transport: {
read: {
url: "/api/BoxJobs"
},
parameterMap: function (data) {
data.parentid = e.data.JobId;
data.appid = e.data.AppId;
return kendo.stringify(data);
}
},
schema: {
model: { id: "JobId" }
},
serverPaging: true,
serverFiltering: true,
serverSorting: true
},
scrollable: false,
sortable: true,
columns: [
{
field: "JobId",
hidden: true
},
{
field: "PercentComplete",
hidden: true
},
{
field: "JobStatusId",
hidden: true
},
{
field: "JobName",
title: "Job Name",
template: "<span>${JobName}</span><img class='health-img-l' id=app-${JobId} title='health' src='' alt='health_png' />",
width: "23%",
filterable: false,
sortable: false
},
{
field: "StartTime",
title: "Start Time",
width: "10%",
editable: false,
filterable: false,
sortable: false
},
{
field: "EndTime",
title: "End Time",
width: "10%",
editable: false,
filterable: false,
sortable: false
},
{
field: "ElapsedTime",
title: "Elapsed</br>Time",
width: "4%",
editable: false,
filterable: false,
sortable: false
},
{
field: "MeanRunTime",
title: "Mean Run</br>Time",
width: "3.5%",
editable: false,
filterable: false,
sortable: false
},
{
field: "PredecessorJobName",
title: "Previous Job",
width: "17%",
filterable: false,
sortable: false
},
{
field: "JobStatusId",
title: "Status",
template: "<img class='health-img-l' id=app-${JobId} title='health' src='' alt='health_png' /><span>${JobStatus}</span>",
editable: false,
filterable: false,
sortable: false
}
],
dataBound: function () {
var grid = this;
grid.tbody.find(">tr").each(function () {
var row = $(this).closest("tr");
var model = grid.dataItem(row);
var img = $(this).find("img");
if (model.JobStatusId == 4 && model.PercentComplete < 100) {
img.attr("src", function() {
return imgSrc + imgGreen;
});
} else if (model.JobStatusId == 4) {
img.attr("src", function() {
return imgSrc + imgAmber;
});
} else if (model.JobStatusId == 7) {
img.attr("src", function() {
return imgSrc + imgIce;
});
} else if (model.JobStatusId == 8) {
img.attr("src", function() {
return imgSrc + imgHold;
});
} else if (model.JobStatusId == 5) {
img.attr("src", function() {
return imgSrc + imgBlue;
});
} else {
img.attr("src", function() {
return imgSrc + imgRed;
});
}
});
}
});
}
Sample top level data:
{"Total":638,
"Data":[
{"JobId":1,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL_BOX","JobType":"box","TimeZone":"Chicago (Central Standard Time)","ParentJobName":null,"ParentJobId":null,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/2014 5:00:02 PM","EndTime":"","ElapsedTime":"00:58:31","JobStatusId":4,"JobStatus":"Running","MeanRunTime":"06:57:04","PercentComplete":14.00,"TotalCount":638.0,"Children":3}
]
}
Sample 2nd level data:
[
{"JobId":63,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL2_BOX","JobType":"box","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL_BOX","ParentJobId":1,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/2014 5:00:06 PM","EndTime":"","ElapsedTime":"00:58:27","JobStatusId":4,"JobStatus":"Running","MeanRunTime":"06:57:00","PercentComplete":14.00,"TotalCount":0.0,"Children":3},
{"JobId":64,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL1_BOX","JobType":"box","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL_BOX","ParentJobId":1,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/2014 5:00:06 PM","EndTime":"","ElapsedTime":"00:58:27","JobStatusId":4,"JobStatus":"Running","MeanRunTime":"01:42:17","PercentComplete":57.00,"TotalCount":0.0,"Children":2},
{"JobId":65,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL3_BOX","JobType":"box","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL_BOX","ParentJobId":1,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/2014 5:00:06 PM","EndTime":"6/2/2014 5:07:42 PM","ElapsedTime":"00:07:36","JobStatusId":5,"JobStatus":"Success","MeanRunTime":"00:03:17","PercentComplete":100.0,"TotalCount":0.0,"Children":5}
]
Sample 3rd level data:
[
{"JobId":265,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL2_S_CLEAN1","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL2_BOX","ParentJobId":63,"PredecessorJobName":"NRS_COL2_S_TOUCH1","PredecessorJobId":266,"StartTime":"","EndTime":"","ElapsedTime":"00:58:31","JobStatusId":7,"JobStatus":"On Ice","PercentComplete":null,"Children":0},
{"JobId":266,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL2_S_TOUCH1","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL2_BOX","ParentJobId":63,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"","EndTime":"","ElapsedTime":"00:58:31","JobStatusId":7,"JobStatus":"On Ice","PercentComplete":null,"Children":0},
{"JobId":267,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL2_A_ZFINSNAMA","TimeZone":"Chicago (Central Standard Time)","ParentJobName":"NRS_COL2_BOX","ParentJobId":63,"PredecessorJobName":"NRS_COL2_S_CLEAN1","PredecessorJobId":265,"StartTime":"6/2/2014 5:02:02 PM","EndTime":"","ElapsedTime":"00:58:31","JobStatusId":4,"JobStatus":"Running","PercentComplete":null,"Children":0}
]
I have no problem with the traditional parent-child hierarchy, but I'm struggling with even how I go about making the detail template behave for it's children.
I would like the template to be appropriate for child/grandchild display - no dropdown indicator if it does not have additional children. I assume that i can evaluate the data on databound, but I'm just not seeing how to do it.