Reputation: 761
I am using MVC 5 and the latest version of Telerik (formerly Kendo) UI for ASP.NET MVC. I am working with hierarchical data. I am attempting to create the TreeView in the _Layout view and populate it with urls or action links.
My current code:
In the _Layout View:
@Html.Partial("_ProductTree")
"_ProductTree" Partial View:
@(Html.Kendo().TreeView().Name("ProductTree")
.DataSource(d => d
.Model(m => m
.Id("ProductId")
.HasChildren("Categories"))
.Read(r => r.Action("_ProductTree", "Home")))
.DataTextField("ProductName"))
Action Method:
[ActionName("_ProductTree")]
public JsonResult GetProductTree()
{
var products = _productBusinessService.GetProducts();
var result = products.Select(p => new
{
p.ProductID,
p.ProductName,
Categories= c.Categories.Any()
}).OrderBy(t => t.ProductName);
return Json(result, JsonRequestBehavior.AllowGet);
}
I am having a number of issues:
I have tried inserting the TreeView Razor code directly into the _Layout view (not using a partial view). I realize that I may need to move the action method into a base controller class and inherit it in every controller to stop it from appending the list to the parent node. If I cant get this working soon, I may have to either use Kendo UI Professional or an open source alternative.
Some of you may be tempted to say that this question has been answered elsewhere. None of the posts I have found address the issues of populating and displaying nested (more than one deep) hierarchical data using the Telerik TreeView.
There is this post
Nested DataSources and TreeView with kendo ui
But it is for the JavaScript version of the TreeView (not the UI for MVC) version and it has not been answered.
Thank you in advance for your help!
Upvotes: 6
Views: 6837
Reputation: 761
The solution in code:
The _Layout view:
@Html.Partial("_ProductTree")
or
@RenderSection("productTree", false)
then in the content view
@section productTree
{
@Html.Partial("_ProductTree")
}
the _ProductTree partial view
@(Html.Kendo().TreeView().Name("ProductTree")
.DataSource(d => d
.Model(m => m
.Id("Id")
.HasChildren("HasChildren")
.Children("Children"))
.Read(r => r.Action("_ProductTree", "Home")))
.DataTextField("Name"))
I moved the action method to a BaseController abstract class that can be inherited by any controller that needs to display the ProductTree TreeView. The data was pulled from a ProductService and a CategoryService and aggregated using LINQ projection into anonymous objects:
[ActionName("_ProductTree")]
public JsonResult GetProductData()
{
var products = _productBusinessService.GetProducts();
foreach (var product in product)
{
foreach (var category in product.Categories)
{
category.ProductTypes =
_productService.GetProductTypes(category.CategoryId);
}
}
var productTreeData = products.Select(p => new
{
Id = p.ProductId,
Name = p.ProductName,
HasChildren = p.Categories.Any(),
Children = p.Categories.Select(c => new
{
Id = c.CategoryId,
Name = c.CategoryName,
HasChildren = c.ProductTypes.Any(),
Children = c.ProductTypes.Select(t => new
{
Id = t.ProductTypeId,
Name = t.ProductTypeName,
HasChildren = false
}).OrderBy(t => t.Name).ToList()
}).OrderBy(c => c.Name).ToList()
}).OrderBy(p => p.Name).ToList();
return Json(productTreeData, JsonRequestBehavior.AllowGet);
}
The result is a 3-deep, fully populated, sorted Telerik UI for ASP.NET Treeview containing the names and IDs of Product >> Category >> ProductType. Turning LoadOnDemand on or off did not seem to make a difference in this case. It should make a difference when using Bind in a TreeView.
Upvotes: 4