MVVM Treeview databinding with multilevel data

5 posts, 0 answers
  1. Fabien
    Fabien avatar
    7 posts
    Member since:
    Jul 2015

    Posted 11 Nov 2015 Link to this post

    Hello,

    My problem is that the documentation is not clear on if/how it is possible to data-bind a TreeView on a multilevel data which is loaded with one call.

    Let's say my data is the following:
    public class TreeLevel1ViewModel
    {
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<TreeLevel2ViewModel> TreeLevel2 { get; set; }
    }
    public class TreeLevel2ViewModel
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public IList<TreeLevel3ViewModel>  TreeLevel3 { get; set; }
        }
    public class TreeLevel3ViewModel
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }

    And I want to call the TreeLevel1ViewModel once already built with the children:

    [HttpGet]
            public HttpResponseMessage Get()
            {
                return Request.CreateResponse(HttpStatusCode.OK,
                    new
                    {
                        data = RetrieveTreeList()
                    });
            }

            private static IEnumerable<TreeLevel1ViewModel> RetrieveTreeList()
            {
                IList<TreeLevel1ViewModel> list = new List<TreeLevel1ViewModel>();
                for (int i = 0; i < 3; i++)
                {
                    TreeLevel1ViewModel level1 = new TreeLevel1ViewModel
                    {
                        Id = i,
                        Name = $"Level1 {i}",
                        TreeLevel2 = new List<TreeLevel2ViewModel>()
                    };

                    for (int j = 0; j < 4; j++)
                    {
                        var level2 = new TreeLevel2ViewModel
                        {
                            Id = j,
                            Name = $"Level2 {i}{j}",
                            TreeLevel3 = new List<TreeLevel3ViewModel>()
                        };

                        for (int k = 0; k < 2; k++)
                        {
                            level2.TreeLevel3.Add(new TreeLevel3ViewModel
                            {
                                Id = k,
                                Name = $"Level2 {i}{j}{k}"
                            });
                        }

                        level1.TreeLevel2.Add(level2);
                    }

                    list.Add(level1);
                }
                return list;
            }

    From there I want to data-bind this data to the TreeView:

    <div id="example">

        <div id="treeview"
             data-role="treeview"
             data-drag-and-drop="false"
             data-text-field="Name"
             data-load-on-demand="false"    
             data-bind="source: treeData">
    </div>
    </div>

        <script type="text/javascript">
            $(function () {
                kendo.bind($("#example"), treeViewModel);
            });
    </script>

    On:

    var treeViewModel = kendo.observable({
        treeData: new kendo.data.HierarchicalDataSource({
            transport: {
                read: {
                    url: "/api/Tree",
                    type: "get",
                    dataType: "json"
                }
            },
            schema: {
                data: "data",
                model: {
                    id: "Id",
                    title: "Name",
                    expanded: false,
                    children: "TreeLevel2"
                }
            }
        })
    });

    This works to display the first and second level, but not the third... I am not surprised as I do not specify the schema further, but when I try something like the following it doesn't work:

    var treeViewModel = kendo.observable({
        treeData: new kendo.data.HierarchicalDataSource({
            transport: {
                read: {
                    url: "/api/Tree",
                    type: "get",
                    dataType: "json"
                }
            },
            schema: {
                data: "data",
                model: {
                    id: "Id",
                    title: "Name",
                    expanded: false,
                    children: {
                        schema: {
                            data: "TreeLevel2",
                            model: {
                                id: "Id",
                                title: "Name",
    children: ...
                        }
                    }
                }
            }
        })
    });

  2. Fabien
    Fabien avatar
    7 posts
    Member since:
    Jul 2015

    Posted 13 Nov 2015 Link to this post

    Hi,

    I realize the message might not be clearly readable because of the formatting, then here are the code blocks:

    The server view models.

    public class TreeLevel1ViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public IList<TreeLevel2ViewModel> TreeLevel2 { get; set; }
    }  
    public class TreeLevel2ViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public IList<TreeLevel3ViewModel>  TreeLevel3 { get; set; }
    }  
    public class TreeLevel3ViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

     The web api

        [HttpGet]
            public HttpResponseMessage Get()
            {
                return Request.CreateResponse(HttpStatusCode.OK,
                    new
                    {
                        data = RetrieveTreeList()
                    });
            }
     
            private static IEnumerable<TreeLevel1ViewModel> RetrieveTreeList()
            {
                IList<TreeLevel1ViewModel> list = new List<TreeLevel1ViewModel>();
                for (int i = 0; i < 3; i++)
                {
                    TreeLevel1ViewModel level1 = new TreeLevel1ViewModel
                    {
                        Id = i,
                        Name = $"Level1 {i}",
                        TreeLevel2 = new List<TreeLevel2ViewModel>()
                    };
     
                    for (int j = 0; j < 4; j++)
                    {
                        var level2 = new TreeLevel2ViewModel
                        {
                            Id = j,
                            Name = $"Level2 {i}{j}",
                            TreeLevel3 = new List<TreeLevel3ViewModel>()
                        };
     
                        for (int k = 0; k < 2; k++)
                        {
                            level2.TreeLevel3.Add(new TreeLevel3ViewModel
                            {
                                Id = k,
                                Name = $"Level2 {i}{j}{k}"
                            });
                        }
     
                        level1.TreeLevel2.Add(level2);
                    }
     
                    list.Add(level1);
                }
                return list;
            }

     

    The HTML

    <div id="example">
     
        <div id="treeview"
             data-role="treeview"
             data-drag-and-drop="false"
             data-text-field="Name"
             data-load-on-demand="false"   
             data-bind="source: treeData">
        </div>
    </div>
     
    <script type="text/javascript">
        $(function () {
            kendo.bind($("#example"), treeViewModel);
        });
    </script>

     

    The Kendo view model

    var treeViewModel = kendo.observable({
        treeData: new kendo.data.HierarchicalDataSource({
            transport: {
                read: {
                    url: "/api/Tree",
                    type: "get",
                    dataType: "json"
                }
            },
            schema: {
                data: "data",
                model: {
                    id: "Id",
                    title: "Name",
                    expanded: false,
                    children: "TreeLevel2"
                }
            }
        })
    });

     

    So, my problem was I want to retrieve the whole tree, with all the levels already loaded with one call to the web api. 

    My only problem is how to bind the data to the tree view using MVVM.

     I tried something like this but it doesn't work:

    var treeViewModel = kendo.observable({
        treeData: new kendo.data.HierarchicalDataSource({
            transport: {
                read: {
                    url: "/api/Tree",
                    type: "get",
                    dataType: "json"
                }
            },
            schema: {
                data: "data",
                model: {
                    id: "Id",
                    title: "Name",
                    expanded: false,
                    children: {
                        schema: {
                            data: "TreeLevel2",
                            model: {
                                id: "Id",
                                title: "Name",
                                children: ...
                        }
                    }
                }
            }
        })
    });

     

     

     

     

     

     

     

  3. Kendo UI is VS 2017 Ready
  4. T. Tsonev
    Admin
    T. Tsonev avatar
    2772 posts

    Posted 16 Nov 2015 Link to this post

    Hi,

    Please accept my apologies for the delayed response.

    It is not possible to bind the TreeView to a heterogeneous model and bind the data in a single call.
    You'll have to fetch the data manually and populate the data source on each level.

    If this is the actual model and not a simplification you should be able to use the same view model type for each level.
    This will allow you to pull all the data with a single call. This also requires setting up a "has children" field. See the docs.

    I hope this helps.

    Regards,
    T. Tsonev
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  5. Fabien
    Fabien avatar
    7 posts
    Member since:
    Jul 2015

    Posted 16 Nov 2015 Link to this post

    Hi,

     

    Thank you for the answer. Unfortunately this example I gave was a simplification of a bit more complex heterogeneous model, I then can't use the same ViewModel.

    I will then have to rebuild the whole tree  every time I have to refresh it (with kendoTreeView()). I work with some code legacy I don't have time to refactor.

     

    Thanks anyway, but maybe it would be an interesting feature to have in the future.

  6. Fabien
    Fabien avatar
    7 posts
    Member since:
    Jul 2015

    Posted 16 Nov 2015 Link to this post

    Hi,

     

    Thanks for your answer. Unfortunately the example I gave is a simplification of a more complex heterogeneous model, I then can't use the same model.

    I will have to refresh the whole tree every time I want it to be refreshed (with kendoTreeView()) but it shouldn't happen often. I work on some code legacy I don't have time or mandate to refactor.

    Anyway thank you, and maybe it would be an interesting feature to have in the future.

Back to Top
Kendo UI is VS 2017 Ready