Kendo UI Grid multi level hierarchy (n-levels of hierarchy)

后端 未结 2 1798
难免孤独
难免孤独 2020-11-29 12:39

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 pare

相关标签:
2条回答
  • 2020-11-29 13:05

    Not sure if this question is still open, but a simple solution is to use recursion in the "DetailInit" function, like below:

    <!DOCTYPE html>
    <html>
    <head>
        <base href="https://demos.telerik.com/kendo-ui/grid/hierarchy">
        <style>html { font-size: 14px; font-family: Arial, Helvetica, sans-serif; }</style>
        <title></title>
        <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.common-material.min.css" />
        <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.material.min.css" />
        <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.material.mobile.min.css" />
    
        <script src="https://kendo.cdn.telerik.com/2018.1.117/js/jquery.min.js"></script>
        <script src="https://kendo.cdn.telerik.com/2018.1.117/js/kendo.all.min.js"></script>
        
    
    </head>
    <body>
    
            <div id="example">
                <div id="grid"></div>          
                <script>
    
    var myData = [{ item: 0, title:"Meat" , items:[
                    { item: 0.1, title:"Beef"},
                    { item: 0.2, title:"Chicken"},
                  ]}, 
                  { item: 1, title:"Vegetables", items:[
                    { item: 1.0, title:"Carrot"},
                    { item: 1.1, title:"Pies", items:[
                      { item: 1.11, title:"Pie1"},
                      { item: 1.12, title:"Pie2"},
                      { item: 1.13, title:"Pie3"}
                     ]},
                  ]}
                 ];
                  
                    $(document).ready(function() {
                        var element = $("#grid").kendoGrid({
                            dataSource: {
                                data: myData
                            },
                            height: 600,
                            sortable: true,
                            pageable: true,
                            detailInit: detailInit1,
                            dataBound: function() {
                                this.expandRow(this.tbody.find("tr.k-master-row").last());
                            },
                            columns: [
                                {
                                    field: "item",
                                    title: "ID",
                                    width: "110px"
                                },
                                {
                                    field: "title",
                                    title: "Food",
                                    width: "110px"
                                }
                            ]
                        });
                    });
    
                    function detailInit1(e) {                  
                        $("<div/>").appendTo(e.detailCell).kendoGrid({
                            dataSource: {
                                data: e.data.items  //data is the current position item, items is its child items
                            },
                            scrollable: false,
                            sortable: true,
                            pageable: true,   
                            detailInit: detailInit1,
                            dataBound: function() {
                                this.expandRow(this.tbody.find("tr.k-master-row").last());
                            },
                            columns: [
                                {
                                    field: "item",
                                    title: "ID",
                                    width: "110px"
                                },
                                {
                                    field: "title",
                                    title: "Food",
                                    width: "110px"
                                }
                            ]
                        });
                    }
                  
                </script>
            </div>
    
    
    </body>
    </html>

    0 讨论(0)
  • 2020-11-29 13:20

    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.

    0 讨论(0)
提交回复
热议问题