This is a migrated thread and some comments may be shown as answers.

MVVM Treeview databinding with multilevel data

2 Answers 218 Views
MVVM
This is a migrated thread and some comments may be shown as answers.
Fabien
Top achievements
Rank 1
Fabien asked on 11 Nov 2015, 08:15 PM

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 Answers, 1 is accepted

Sort by
0
Fabien
Top achievements
Rank 1
answered on 13 Nov 2015, 01:48 PM

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

 

 

 

 

 

 

 

0
T. Tsonev
Telerik team
answered on 16 Nov 2015, 08:51 AM
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!
 
Tags
MVVM
Asked by
Fabien
Top achievements
Rank 1
Answers by
Fabien
Top achievements
Rank 1
T. Tsonev
Telerik team
Share this question
or