Kendo UI网格多级层次结构(层次结构的n级)

我正在使用Kendo UI Grid并且当前正确显示父子记录。 然而,事实certificate我实际上需要显示n级与严格的父级。 不是每个记录都会有孩子,但有些会有多个级别。

当前网格代码:

var jgrid = $("#boxesgrid").kendoGrid({ columns: [ { field: "JobId", hidden: true }, { field: "PercentComplete", hidden: true }, { field: "JobStatusId", hidden: true }, { field: "AppName", title: "App", template: "${AppName}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: "health_png${JobStatus}", 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"); 

目前的儿童网格:

 function detailInit(e) { $("
").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: "${JobName}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
Time", width: "4%", editable: false, filterable: false, sortable: false }, { field: "MeanRunTime", title: "Mean Run
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: "health_png${JobStatus}", 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; }); } }); } }); }

顶级数据示例:

  {"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} ] } 

第二级数据样本:

 [ {"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} ] 

样本第3级数据:

 [ {"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} ] 

我对传统的父子层次结构没有任何问题,但我正在努力解决如何使细节模板为其子项运行的问题。

我希望模板适合子/孙子显示 – 如果没有额外的孩子,则没有下拉指示器。 我假设我可以评估数据绑定上的数据,但我只是没有看到如何做到这一点。

花了一段时间,但我终于在Telerik的窥视中得到了一些答案。 我只是最难以解决问题。

Vladimir(在Telerik)建议我在detailInit函数中使用自定义ajax调用,使用成功函数来确定我是否有要考虑的子数据。 由于我无论如何都需要细节网格,因此我将子检查移动到另一个创建细节网格的函数中。 如果我找到子数据,我会将detailInit参数添加到新网格中。 如果没有,我只是渲染新的细节网格。

ajax initDetail函数:

 function detailInit(e) { var eventData = e; $.ajax({ url: apiUrl + "ProcessJobs", type: "POST", data: {BoxId: e.data.JobId, AppId: e.data.AppId}, dataType: "json", success: function(data, status, xhr) { initializeDetailGrid(eventData, data); } } 

使用子项检查构建新详细信息网格的function:

 function initializeDetailGrid(e, result) { var moreChildren = result[0].HasChildren; var gridBaseOptions = { dataSource: result, scrollable: false, sortable: true, columns: [ { field: "ParentJobId", title: "Parent Job" }, { field: "JobId", title: "Job Id" }, { field: "JobName", title: "Job Name", }, { field: "JobStatus", title: "Status" }, { field: "JobStatusId", title: "Status Code" }, { field: "HasChildren", title: "Has Children" }, { field: "ChildrenCount", title: "Child Jobs" } ] }; var gridOptions = {}; if (moreChildren) { gridOptions = $.extend({}, gridBaseOptions, { detailInit: detailInit }); } else { gridOptions = gridBaseOptions; }; $("
").appendTo(e.detailCell).kendoGrid(gridOptions); };

为了完整性,这里是示例项目的完整页面和示例数据。 它是一个基于.Net MVC4的网站,使用Web API服务为客户端提供数据和Kendo UI。

这是页面代码:

 @{ ViewBag.Title = "n-level Grid"; }  
Line of Business
Application
Filter

这个示例应用程序的数据实际上是硬编码的,但我仍然通过Web API返回它。 以下是最高级别数据的示例:

 new Process {JobId = 108, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_108", ParentJobName = null, ParentJobId = null, JobStatusId = 4, JobStatus = "Running", ChildrenCount = 3, HasChildren = true}, new Process {JobId = 109, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_109", ParentJobName = null, ParentJobId = null, JobStatusId = 5, JobStatus = "Success", ChildrenCount = 4, HasChildren = true}, new Process {JobId = 110, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_110", ParentJobName = null, ParentJobId = null, JobStatusId = 4, JobStatus = "Running", ChildrenCount = 2, HasChildren = true}, new Process {JobId = 111, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_111", ParentJobName = null, ParentJobId = null, JobStatusId = 5, JobStatus = "Success", ChildrenCount = 5, HasChildren = true}, 

这是一些二级数据(子数据):

 new Process {JobId = 1037, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_1037", ParentJobName = "job_109", ParentJobId = 109, JobStatusId = 4, JobStatus = "Running", ChildrenCount = 0, HasChildren = false}, new Process {JobId = 1038, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_1038", ParentJobName = "job_109", ParentJobId = 109, JobStatusId = 4, JobStatus = "Running", ChildrenCount = 0, HasChildren = false}, new Process {JobId = 1039, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_1039", ParentJobName = "job_110", ParentJobId = 110, JobStatusId = 4, JobStatus = "Running", ChildrenCount = 2, HasChildren = true}, new Process {JobId = 1040, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_1040", ParentJobName = "job_110", ParentJobId = 110, JobStatusId = 4, JobStatus = "Running", ChildrenCount = 2, HasChildren = true}, 

一些第三级数据(孙子):

 new Process {JobId = 5000, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_5000", ParentJobName = "job_1039", ParentJobId = 1039, JobStatusId = 5, JobStatus = "Success", ChildrenCount = 0, HasChildren = false}, new Process {JobId = 5001, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_5001", ParentJobName = "job_1039", ParentJobId = 1039, JobStatusId = 5, JobStatus = "Success", ChildrenCount = 0, HasChildren = false}, new Process {JobId = 5002, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_5002", ParentJobName = "job_1040", ParentJobId = 1040, JobStatusId = 5, JobStatus = "Success", ChildrenCount = 0, HasChildren = false}, new Process {JobId = 5003, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_5003", ParentJobName = "job_1040", ParentJobId = 1040, JobStatusId = 5, JobStatus = "Success", ChildrenCount = 0, HasChildren = false}, new Process {JobId = 5004, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_5004", ParentJobName = "job_1041", ParentJobId = 1041, JobStatusId = 5, JobStatus = "Success", ChildrenCount = 1, HasChildren = true}, 

等等…

它在我的测试中正常工作4个级别。 我将要解决的多个嵌套网格存在格式问题。

不确定这个问题是否仍然是开放的,但一个简单的解决方案是在“DetailInit”函数中使用递归,如下所示: