Kendo UI Grid 多级层次结构(n 级层次结构) [英] Kendo UI Grid multi level hierarchy (n-levels of hierarchy)

查看:26
本文介绍了Kendo UI Grid 多级层次结构(n 级层次结构)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Kendo UI Grid 并且当前正确显示父子记录.然而,事实证明我实际上需要显示 n 级与严格的父子级.并非每条记录都会有子项,但有些记录会有多个级别.

当前网格代码:

 var jgrid = $("#boxesgrid").kendoGrid({列: [{字段:作业ID",隐藏:真实},{字段:百分比完成",隐藏:真实},{字段:JobStatusId",隐藏:真实},{字段:应用名称",title: "应用程序",模板:<span>${AppName}</span><img class='health-img-r' id=app-${JobId} title='health' src='' alt='health_png'/>",宽度:5%",可假,可排序:假},{字段:工作名称",title: "框名",宽度:17%",可过滤:假},{字段:开始时间",title: "开始时间",宽度:14%",可过滤:假},{字段:结束时间",title: "结束时间",宽度:14%",可过滤:假},{字段:JobStatusId",title: "状态",模板:<img class='health-img-l' id=app-${JobId} title='health' src='' alt='health_png'/><span>${JobStatus}</跨度>",可假,可过滤:假}],可排序:{模式:单",允许未排序:真},可分页:{页面大小:[50],数字:真,刷新:真实,页面大小:50},自动绑定:假,可滚动:假,可调整大小:真实,细节初始化:细节初始化,数据源:boxesDataSource,数据绑定:函数(){var grid = this;grid.tbody.find(">tr").each(function () {var row = $(this).closest("tr");var 模型 = grid.dataItem(row);var img = $(this).find("img");if (model.JobStatusId == 4 && model.PercentComplete < 100) {img.attr("src", function() {返回 imgSrc + imgGreen;});} else if (model.JobStatusId == 4) {img.attr("src", function() {返回 imgSrc + imgAmber;});} else if (model.JobStatusId == 7) {img.attr("src", function() {返回 imgSrc + imgIce;});} else if (model.JobStatusId == 8) {img.attr("src", function() {返回 imgSrc + imgHold;});} else if (model.JobStatusId == 5) {img.attr("src", function() {返回 imgSrc + imgBlue;});} 别的 {img.attr("src", function() {返回 imgSrc + imgRed;});}});}}).data("kendoGrid");

当前子网格:

function detailInit(e) {$("

").appendTo(e.detailCell).kendoGrid({数据源: {运输: {读: {url: "/api/BoxJobs"},参数映射:函数(数据){data.parentid = e.data.JobId;data.appid = e.data.AppId;返回 kendo.stringify(data);}},架构:{模型:{ id:工作ID"}},服务器分页:真,服务器过滤:真,服务器排序:true},可滚动:假,可排序:真实,列: [{字段:作业ID",隐藏:真实},{字段:百分比完成",隐藏:真实},{字段:JobStatusId",隐藏:真实},{字段:工作名称",title: "职位名称",模板:<span>${JobName}</span><img class='health-img-l' id=app-${JobId} title='health' src='' alt='health_png'/>",宽度:23%",可过滤:假,可排序:假},{字段:开始时间",title: "开始时间",宽度:10%",可假,可过滤:假,可排序:假},{字段:结束时间",title: "结束时间",宽度:10%",可假,可过滤:假,可排序:假},{字段:已用时间",标题:经过的时间",宽度:4%",可假,可过滤:假,可排序:假},{字段:平均运行时间",标题:平均运行时间",宽度:3.5%",可假,可过滤:假,可排序:假},{字段:PredecessorJobName",title: "以前的工作",宽度:17%",可过滤:假,可排序:假},{字段:JobStatusId",title: "状态",模板:<img class='health-img-l' id=app-${JobId} title='health' src='' alt='health_png'/><span>${JobStatus}</跨度>",可假,可过滤:假,可排序:假}],数据绑定:函数(){var grid = this;grid.tbody.find(">tr").each(function () {var row = $(this).closest("tr");var 模型 = grid.dataItem(row);var img = $(this).find("img");if (model.JobStatusId == 4 && model.PercentComplete < 100) {img.attr("src", function() {返回 imgSrc + imgGreen;});} else if (model.JobStatusId == 4) {img.attr("src", function() {返回 imgSrc + imgAmber;});} else if (model.JobStatusId == 7) {img.attr("src", function() {返回 imgSrc + imgIce;});} else if (model.JobStatusId == 8) {img.attr("src", function() {返回 imgSrc + imgHold;});} else if (model.JobStatusId == 5) {img.attr("src", function() {返回 imgSrc + imgBlue;});} 别的 {img.attr("src", function() {返回 imgSrc + imgRed;});}});}});}

样本顶级数据:

 {"Total":638,数据":[{"JobId":1,"AppId":1,"AppName":"APP1","LobId":2,"LobName":"LOB2","JobName":"NRS_COL_BOX","JobType":"box","TimeZone":"芝加哥(中部标准时间)","ParentJobName":null,"ParentJobId":null,"PredecessorJobName":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":"芝加哥(中部标准时间)","ParentJobName":"NRS_COL_BOX","ParentJobId":1,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/20145: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":"芝加哥(中部标准时间)","ParentJobName":"NRS_COL_BOX","ParentJobId":1,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/20145: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":"芝加哥(中部标准时间)","ParentJobName":"NRS_COL_BOX","ParentJobId":1,"PredecessorJobName":null,"PredecessorJobId":null,"StartTime":"6/2/20145:00:06 PM","EndTime":"6/2/2014 5:07:42 PM","ElapsedTime":"00:07:36","JobStatusId":5,"JobStatus":"成功","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":"芝加哥 (中央标准时间)","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":"芝加哥 (中央标准时间)","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":"芝加哥 (中央标准时间)","ParentJobName":"NRS_COL2_BOX","ParentJobId":63,"PredecessorJobName":"NRS_COL2_S_CLEAN1","PredecessorJobId":265,"StartTime":"6/2/2014 PM 5:02:02","EndTime":"","ElapsedTime":"00:58:31","JobStatusId":4,"JobStatus":"Running","PercentComplete":null,"Children":0}]

我对传统的父子层次结构没有任何问题,但我什至在如何让细节模板为它的孩子表现的过程中挣扎.

我希望模板适合子/孙显示 - 如果没有其他子项,则没有下拉指示符.我假设我可以评估 databound 上的数据,但我只是不知道如何去做.

解决方案

这花了一段时间,但我终于在 Telerik 的窥视者的一些指导下找到了答案.我只是在最困难的时间里思考解决方案.

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

ajax initDetail 函数:

function detailInit(e) {var eventData = e;$.ajax({url: apiUrl + "ProcessJobs",类型:POST",数据:{BoxId:e.data.JobId,AppId:e.data.AppId},数据类型:json",成功:功能(数据,状态,xhr){initializeDetailGrid(eventData, 数据);}}

使用检查子项构建新细节网格的功能:

function initializeDetailGrid(e, result) {var moreChildren = result[0].HasChildren;var gridBaseOptions = {数据源:结果,可滚动:假,可排序:真实,列: [{字段:ParentJobId",书名:《父母的工作》},{字段:作业ID",标题:作业 ID"},{字段:工作名称",title: "职位名称",},{字段:工作状态",书名:《状态》},{字段:JobStatusId",标题:状态码"},{字段:HasChildren",书名:《有孩子》},{字段:ChildrenCount",标题:儿童工作"}]};var gridOptions = {};如果(更多儿童){gridOptions = $.extend({}, gridBaseOptions, { detailInit: detailInit });} 别的 {gridOptions = gridBaseOptions;};$("

").appendTo(e.detailCell).kendoGrid(gridOptions);};

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

这是页面代码:

@{ViewBag.Title = "n 级网格";}<script type="text/javascript">$(document).ready(function () {var isParent, appId, lobId, boxId;var apiUrl = '@ViewBag.ApiUrl';var lobDataSource = new kendo.data.DataSource({运输: {读: {url: apiUrl + "Lob"}},架构:{模型: {id: "LobId",hasChildren: "HasChildren"}}});var appsDataSource = new kendo.data.DataSource({运输: {读: {url: apiUrl + "应用程序"},参数映射:函数(数据,动作){如果(动作 ===阅读"){数据.lobid = lobId;data.parent = isParent;返回数据;} 别的 {返回数据;}}}});var filterDataSource = new kendo.data.DataSource({运输: {读: {url: apiUrl + "主题"}},架构:{模型:{ id:过滤器Id"}}});var boxDataSource = new kendo.data.DataSource({运输: {读: {url: apiUrl + "进程"},参数映射:函数(数据){数据.appid = appId;data.parent = isParent;数据.lobid = lobId;返回 kendo.stringify(data);}},架构:{数据:数据",总计:总计",模型:{ id:工作ID"}},服务器分页:真,服务器过滤:真,服务器排序:true});var lobnav = $("#lobnav").kendoTreeView({选择:功能(e){无功树=这个;var src = tree.dataItem(e.node);lobId = src.LobId;isParent = src.HasChildren;},改变:功能(e){appsDataSource.read();},数据源: {运输: {读: {url: apiUrl + "Lob"}},架构:{模型: {id: "LobId",hasChildren: "HasChildren"}}},按需加载:假,数据文本字段:LobName"});var appnav = $("#lobapp").kendoListView({可选:单",自动绑定:假,改变:函数(){var idx = this.select().index();var itm = this.dataSource.view()[idx];appId = itm.AppId;boxDataSource.query({页数:1,页面大小:10});},模板:<div class='pointercursor'>${AppName}</div>",数据源:appsDataSource});var jobsfilter = $("#jobfilter").kendoListView({可选:单",按需加载:假,模板:<div class='pointercursor' id=${FilterId}>${FilterName}</div>",数据源:过滤器数据源,数据绑定:函数(){var dsource = $("#jobfilter").data("kendoListView").dataSource;if (dsource.at(0).FilterName !== "All") {dsource.insert(0, { FilterId: 0, FilterName: "All" });}},改变:函数(){var itm = this.select().index(), dataItem = this.dataSource.view()[itm];var appDs = appsDataSource.view(), apps = $("#lobapp").data("kendoListView"),selected = $.map(apps.select(), function (item) {返回 appDs[$(item).index()].AppName;});if (selected.length > 0) {如果 (dataItem.FilterId !== 0) {var $filter = new Array();$filter.push({ field: "JobStatusId", operator: "eq", value: dataItem.FilterId });jgrid.dataSource.filter($filter);} 别的 {jgrid.dataSource.filter({});}}}});var jgrid = $("#boxesgrid").kendoGrid({列: [{字段:应用名称",标题:应用程序"},{字段:作业ID",标题:作业 ID"},{字段:工作名称",title: "职位名称",},{字段:工作状态",书名:《状态》},{字段:JobStatusId",标题:状态码"},{字段:HasChildren",书名:《有孩子》},{字段:ChildrenCount",标题:儿童工作"}],可排序:{模式:单",允许未排序:真},可分页:{页面大小:[10],数字:真,刷新:真实,页面大小:10},自动绑定:假,可滚动:假,可调整大小:真实,细节初始化:细节初始化,数据源:boxesDataSource}).data("kendoGrid");函数细节初始化(e){var eventData = e;$.ajax({url: apiUrl + "ProcessJobs",类型:POST",数据:{BoxId:e.data.JobId,AppId:e.data.AppId},数据类型:json",成功:功能(数据,状态,xhr){initializeDetailGrid(eventData, 数据);}});};函数 initializeDetailGrid(e, 结果) {var moreChildren = result[0].HasChildren;var gridBaseOptions = {数据源:结果,可滚动:假,可排序:真实,列: [{字段:ParentJobId",书名:《父母的工作》},{字段:作业ID",标题:作业 ID"},{字段:工作名称",title: "职位名称",},{字段:工作状态",书名:《状态》},{字段:JobStatusId",标题:状态码"},{字段:HasChildren",书名:《有孩子》},{字段:ChildrenCount",标题:儿童工作"}]};var gridOptions = {};如果(更多儿童){gridOptions = $.extend({}, gridBaseOptions, { detailInit: detailInit });} 别的 {gridOptions = gridBaseOptions;};$("

").appendTo(e.detailCell).kendoGrid(gridOptions);};});<div class="col-md-2"><div class="panel panel-default"><div class="panel-heading">业务线</div><div class="panel-body" id="lobnav"></div>

<div class="panel panel-default"><div class="panel-heading">应用程序</div><div class="panel-body" id="lobapp"></div>

<div class="panel panel-default"><div class="panel-heading">过滤器</div><div class="panel-body" id="jobfilter">

<div class="col-md-10"><div id="boxesgrid"></div>

这个示例应用程序的数据实际上是硬编码的,但我仍然通过 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 = "运行", 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 = "运行", 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 = "运行", ChildrenCount = 2, HasChildren = true},

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

new Process {JobId = 5000, AppId = 1, AppName = "App1", LobId = 2, LobName = "Lob2", JobName = "job_5000", ParentJobName = "job_1039", ParentJobId = 1039, JobStatusId= 5, JobStatus = "成功", 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 = "成功", 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 = "成功", 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 = "成功", 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 = "成功", ChildrenCount = 1, HasChildren = true},

等等……

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

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.

解决方案

It took a while, but I finally worked out an answer with some guidance from the peeps at Telerik. I was just having the hardest time getting my head around the solution.

Vladimir (at Telerik) suggested that I use a custom ajax call in the detailInit function using a function on success to determine if I had child data to consider. Since I needed the detail grid no matter what, I moved the child check into another function that creates the detail grid. If I find child data, I add a detailInit parameter to the new grid. If not, I simply render the new detail grid.

The ajax initDetail function:

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);
                }
            }

The function to build the new detail grid with the check for children:

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;
            };
            $("<div/>").appendTo(e.detailCell).kendoGrid(gridOptions);
        };

For completeness, here is the full page and example data from the sample project. It is a .Net MVC4 based website, using Web API services for data and Kendo UI for the client.

Here is the page code:

@{
    ViewBag.Title = "n-level Grid";
}

<script type="text/javascript">
    $(document).ready(function () {
        var isParent, appId, lobId, boxId;
        var apiUrl = '@ViewBag.ApiUrl';

        var lobDataSource = new kendo.data.DataSource({
            transport: {
                read: {
                    url: apiUrl + "Lob"
                }
            },
            schema: {
                model: {
                    id: "LobId",
                    hasChildren: "HasChildren"
                }
            }
        });

        var appsDataSource = new kendo.data.DataSource({
            transport: {
                read: {
                    url: apiUrl + "App"
                },
                parameterMap: function (data, action) {
                    if (action === "read") {
                        data.lobid = lobId;
                        data.parent = isParent;
                        return data;
                    } else {
                        return data;
                    }
                }
            }
        });

        var filterDataSource = new kendo.data.DataSource({
            transport: {
                read: {
                    url: apiUrl + "Theme"
                }
            },
            schema: {
                model: { id: "FilterId" }
            }
        });

        var boxesDataSource = new kendo.data.DataSource({
            transport: {
                read: {
                    url: apiUrl + "Process"
                },
                parameterMap: function (data) {
                    data.appid = appId;
                    data.parent = isParent;
                    data.lobid = lobId;
                    return kendo.stringify(data);
                }
            },
            schema: {
                data: "Data",
                total: "Total",
                model: { id: "JobId" }
            },
            serverPaging: true,
            serverFiltering: true,
            serverSorting: true
        });

        var lobnav = $("#lobnav").kendoTreeView({
            select: function (e) {
                var tree = this;
                var src = tree.dataItem(e.node);
                lobId = src.LobId;
                isParent = src.HasChildren;
            },
            change: function (e) {
                appsDataSource.read();
            },
            dataSource: {
                transport: {
                    read: {
                        url: apiUrl + "Lob"
                    }
                },
                schema: {
                    model: {
                        id: "LobId",
                        hasChildren: "HasChildren"
                    }
                }
            },
            loadOnDemand: false,
            dataTextField: "LobName"
        });

        var appnav = $("#lobapp").kendoListView({
            selectable: "single",
            autoBind: false,
            change: function () {
                var idx = this.select().index();
                var itm = this.dataSource.view()[idx];
                appId = itm.AppId;
                boxesDataSource.query({
                    page: 1,
                    pageSize: 10
                });
            },
            template: "<div class='pointercursor'>${AppName}</div>",
            dataSource: appsDataSource
        });

        var jobsfilter = $("#jobfilter").kendoListView({
            selectable: "single",
            loadOnDemand: false,
            template: "<div class='pointercursor' id=${FilterId}>${FilterName}</div>",
            dataSource: filterDataSource,
            dataBound: function () {
                var dsource = $("#jobfilter").data("kendoListView").dataSource;
                if (dsource.at(0).FilterName !== "All") {
                    dsource.insert(0, { FilterId: 0, FilterName: "All" });
                }
            },
            change: function () {
                var itm = this.select().index(), dataItem = this.dataSource.view()[itm];
                var appDs = appsDataSource.view(), apps = $("#lobapp").data("kendoListView"),
                    selected = $.map(apps.select(), function (item) {
                        return appDs[$(item).index()].AppName;
                    });
                if (selected.length > 0) {
                    if (dataItem.FilterId !== 0) {
                        var $filter = new Array();
                        $filter.push({ field: "JobStatusId", operator: "eq", value: dataItem.FilterId });
                        jgrid.dataSource.filter($filter);
                    } else {
                        jgrid.dataSource.filter({});
                    }
                }
            }
        });

        var jgrid = $("#boxesgrid").kendoGrid({
            columns: [
                {
                    field: "AppName",
                    title: "App"
                },
                {
                    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"
                }
            ],
            sortable: {
                mode: "single",
                allowUnsort: true
            },
            pageable: {
                pageSizes: [10],
                numeric: true,
                refresh: true,
                pageSize: 10
            },
            autoBind: false,
            scrollable: false,
            resizable: true,
            detailInit: detailInit,
            dataSource: boxesDataSource
        }).data("kendoGrid");

        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 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;
            };
            $("<div/>").appendTo(e.detailCell).kendoGrid(gridOptions);
        };
    });
</script>

<div class="col-md-2">
    <div class="panel panel-default">
        <div class="panel-heading">Line of Business</div>
        <div class="panel-body" id="lobnav"></div>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">Application</div>
        <div class="panel-body" id="lobapp"></div>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">Filter</div>
        <div class="panel-body" id="jobfilter">
        </div>
    </div>
</div>
<div class="col-md-10">
    <div id="boxesgrid"></div>
</div>

The data is actually hardcoded for this sample app, but I still return it via Web API. Here is a sample of the highest level data:

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},

Here is some second level data (child data):

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},

Some of the 3rd level data (grandchildren):

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},

And so on...

It is working correctly for 4 levels in my testing. There are formatting issues with the multiple nested grids that I will be addressing.

这篇关于Kendo UI Grid 多级层次结构(n 级层次结构)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆