I'm trying to create a Kendo treeview that gets populated from my controller (PropertyController).
The part I'm stuck at is how to format my data in the controller. How could I create a treeview three items deep and pass that to my view to be displayed in the treeview?
#(Html.Kendo().TreeView()
.Name("treeview")
.Events(events => events
.DragStart("PartnershipPage.OnDragStart")
.Drop("PartnershipPage.OnDrop")
.DragEnd("PartnershipPage.OnDragEnd")
)
.HighlightPath(true)
.DragAndDrop(true)
.DataSource(dataSource => dataSource
.Read(read => read
.Action("Index","Tree")
)
)
)
I've included the controller to see if I'm doing it correctly. All that is happening so far is the JSON is being displayed on the screen as text.
Controller:
public ActionResult Index()
{
var org = new Entities();
var eList = new List<Entity>();
var entity1 = new Entity
{
Id = 1,
Name = "LLC-A",
parentId = 0
};
eList.Add(entity1);
var entity2 = new Entity
{
Id = 2,
Name = "LLC-B",
parentId = 0
};
eList.Add(entity2);
var entity3 = new Entity
{
Id = 1,
Name = "LLC-C",
parentId = 2
};
eList.Add(entity3);
var entity4 = new Entity
{
Id = 1,
Name = "LLC-D",
parentId = 2
};
eList.Add(entity4);
org.Entity = eList;
var test = from x in org.Entity
where (x.Name != null)
select new
{
Id = x.Id,
Name = x.Name,
parentId = x.parentId
};
;
return Json(test, JsonRequestBehavior.AllowGet);
}
From: Kendo Site
<%= Html.Kendo().TreeView()
.Name("TreeView")
.BindTo(Model, mapping => mapping
.For<Customer>(binding => binding
.Children(c => c.Orders) // The "child" items will be bound to the the "Orders" property
.ItemDataBound((item, c) => item.Text = c.ContactName) // Map "Customer" properties to TreeViewItem properties
)
.For<Order<(binding => binding
.Children(o => null) // "Orders" do not have child objects so return "null"
.ItemDataBound((item, o) => item.Text = o.OrderID.ToString()) // Map "Order" properties to TreeViewItem properties
)
)
%>
You could put your entities into a list called for example, "myEntities" and return that from the controller to the view:
public ActionResult Index()
{
var ents = getMyEntities(); // some method you have to return the list of your entities
return ents;
}
Then in your view, you can loop through all the Entities in your Model:
#(Html.Kendo().TreeView()
.Name("TreeView")
.Items(treeview =>
{
foreach (var entity in Model)
{
var entityName = entity.Name;
var children = entity.Children;
treeview.Add().Text(entityName ).Expanded(false).Items(branch =>
{
if (children != null)
{
foreach (var child in children)
{
branch.Add().Text(child);
}
}
});
}
}
)
)
I used children because I found it easier to use than parent and so I would change my Entities to something like this:
var entity4 = new Entity
{
Id = 1,
Name = "LLC-D",
Children = <list of children names ... >
};
You can see how I did mine here: Populate KendoUI Treeview with RavenDB Documents
Hope this helps.
Edit in response to: How can I display children of children?
I ran into the same problem as you describe (displaying children of children). Here is how I did it after I had the problem of displaying children of children:
I used EntityFramework:
The DB context class:
public class EntityDBContext : DbContext
{
public DbSet<MyEntity> Entities { get; set; }
}
Controller:
public JsonResult EntitiesForTreeView(int? id)
{
// Here I am using EntityFramework
var entitiesContext = new EntityDBContext();
var myEntity= from e in entitiesContext.Entities
where (id.HasValue ? e.Parent == id : e.Parent == null)
select new
{
id = e.Id,
Name = e.Name,
hasChildren = e.Id
};
return Json(myEntity, JsonRequestBehavior.AllowGet);
}
And the View:
#(Html.Kendo().TreeView()
.Name("treeview")
.DataTextField("Name")
.LoadOnDemand(true)
.HighlightPath(true)
.DataSource(dataSource => dataSource
.Read(read => read
.Action("EntitiesForTreeView", "SiteMap")
)
)
.Checkboxes(true)
)
Hope this helps. Sorry if there is something stupid - I've only been doing web development for 3 months so unmark as answer if needed. Let me know if I can help further. PS: I should mention that after implementing the solution I have shown above, I noticed that the nodes on my tree all have the "+" sign... regardless of whether or not they have any children. If you know how to fix this, please let me know :)
Related
I been trying to change the value of RouteAttr.RoutedForRole if it is equal to
SHead but I checked in run time and the query was not changed even though it went to the foreach loop and there were valid entries. I also tried adding the foreach loop in the view but it didn't change anything.
public ViewResult Index()
{
IQueryable<ServiceRequestViewModel> query;
query = from c in context.ServiceRequests
select new ServiceRequestViewModel
{
ServiceRequestId = c.ServiceRequestId,
ServiceDescription = c.ServiceDescription,
RequestNumber = c.RequestNumber,
Title = c.Title,
RouteAttr = c.RouteAttr,
LogAttr = c.LogAttr
};
foreach (var item in query)
{
if (item.RouteAttr.RoutedForRole == WorkflowRole.SHead)
{
item.RouteAttr.RoutedForRole = WorkflowRole.HRManager;
}
}
return View(query);
}
Below is my gridview.
#Html.Grid(Model).Columns(col =>
{
col.Add(o => o.ServiceRequestId)
.Encoded(false)
.Sanitized(false)
.Filterable(true)
.Titled("SRF No.")
.SetWidth(150)
.RenderValueAs(o => Html.ActionLink(o.RequestNumber, "Details", new { id = o.ServiceRequestId }));
col.Add(o => o.Title)
.Filterable(true)
.SetWidth(400)
.Titled("Title");
col.Add(o => o.LogAttr.CreatedBy)
.Filterable(true)
.Titled("Requestor");
col.Add(o => o.RouteAttr.RoutedForRole)
.Filterable(true)
.Titled("Status");
}).WithPaging(10).Sortable(true)
I've been told in the comments why it's not returning so now I want to know how to update an item in iqueryable and return it in view.
Just like what #Enigmativity said in the comments, I changed the query into an array.
var data = query.ToArray();
He suggested I return data but it didn't work since ServiceRequestViewModel requires an IQueryable type. So I changed it back to IQueryable type so I can return it to view.
var queryable = data.AsQueryable();
I'm trying to follow this example here
http://docs.telerik.com/kendo-ui/getting-started/using-kendo-with/aspnet-mvc/helpers/treeview/ajax-binding
However, whenever I try to modify their code, I get an error saying
Error 2 'Kendo.Mvc.UI.Fluent.ReadOnlyDataSourceBuilder' does not contain a definition for 'Model' and no extension method 'Model' accepting a first argument of type 'Kendo.Mvc.UI.Fluent.ReadOnlyDataSourceBuilder' could be found (are you missing a using directive or an assembly reference?) c:\Users\Michael\Google Drive\Work\Companies\Clickable Community\dhvs\Clickable Community\Development\Portal\ClickableCommunity.Web\Views\Shared_Layout.cshtml 34 ClickableCommunity.Web
Here is my code
#(Html.Kendo().TreeView()
.Name("treeview")
// The property that specifies the text of the node
.DataTextField("Name")
.DataSource(dataSource => dataSource
.Model(model => model
// The property that uniquely identieis a node.
// The value of this property is the argument of the action method
.Id("Id")
// the boolean property that tells whether a node has children
.HasChildren("HasChildren")
)
.Read(read => read
// The action method which will return JSON
.Action("ReadCats", "Home")
)
)
)
and what I'm doing in my controller
public JsonResult ReadCats()
{
var categories = _entityLogic.GetActiveCategories();
var jsonResult = categories.Select(cat => new
{
Id = cat.Id,
Name = cat.Name,
HasChildren = categories.Where(c => c.ParentCategory == cat.Id).Any(),
ParentId = cat.ParentCategory
}).ToList();
return Json(jsonResult, JsonRequestBehavior.AllowGet);
}
Basically, I have a table that stores and ID, name, and parentcategory (the id of the parent category) and I'm trying to bind a treeview to all my parent child nodes. Thanks in advance.
Edit
So I still cannot get this. I keep getting the same error. I can't put #model namespace because it gives me an error saying it is a namespace but used like a type. Here is my entire code. Thanks,
#model ClickableCommunity.Web.Models.Public.HomeModel
#using ClickableCommunity.Core.Models.Data
#using Kendo.Mvc.UI
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
#(Html.Kendo().TreeView()
.Name("treeview")
// The property that specifies the text of the node
.DataTextField("Name")
.DataSource(dataSource => dataSource
.Model(model => model
// The property that uniquely identieis a node.
// The value of this property is the argument of the action method
.Id("Id")
// the boolean property that tells whether a node has children
.HasChildren("HasChildren")
)
.Read(read => read
// The action method which will return JSON
.Action("ReadCats", "Home")
)
)
)
<ul>
#foreach (var item in Model.CategoryEntities)
{
<li>
#item.Name
</li>
}
</ul>
And here is my controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using ClickableCommunity.Core.Contracts.Logging;
using ClickableCommunity.Core.Contracts.Logic;
using ClickableCommunity.Web.Models.Public;
namespace ClickableCommunity.Web.Controllers
{
public class HomeController : BaseController
{
private readonly IEntityLogic _entityLogic;
private readonly IGeogrpaphyLogic _geoLogic;
private readonly IUserLogic _userLogic;
public HomeController(ISystemLogger logger, IEntityLogic entityLogic, IUserLogic userLogic, IGeogrpaphyLogic geoLogic) : base(logger)
{
_entityLogic = entityLogic;
_userLogic = userLogic;
_geoLogic = geoLogic;
}
public ActionResult Index()
{
var catEnts = new List<HomeModel.CategoryEntitiesList>();
var model = new HomeModel
{
AvailableCategories = _entityLogic.GetActiveCategories()
, Entities = _entityLogic.GetActiveEntities()
, States = _geoLogic.GetAllStates()
};
var tempCe = new HomeModel.CategoryEntitiesList();
foreach (var i in model.AvailableCategories.Where(c => c.ParentCategory == null))
{
tempCe = new HomeModel.CategoryEntitiesList();
tempCe.Name = i.Name;
tempCe.ParentCategory = i.ParentCategory;
tempCe.Id = i.Id;
tempCe.HasChildren = model.AvailableCategories.Where(a => a.ParentCategory == i.Id).Any();
catEnts.Add(tempCe);
}
model.CategoryEntities = catEnts;
return View(model);
//return View();
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
public JsonResult GetChildTreeViewData(int? id)
{
var categories = _entityLogic.GetActiveCategories();
if (id != null)
{
categories = categories.Where(c => c.ParentCategory == id);
}
var jsonResult = categories.Select(cat => new
{
Id = cat.Id,
Name = cat.Name,
HasChildren = categories.Where(c => c.ParentCategory == cat.Id).Any(),
ParentCategory = cat.ParentCategory
}).ToList();
return Json(jsonResult, JsonRequestBehavior.AllowGet);
}
}
}
Your View should define a Model in order for this to work
Add this line to the top of your View:
#model categories //or whatever namespace your Entity categoies are in
this should work fine!!
I have a table in database
I've been able to show the list of TypeName in my dropdownlist in my View
Currently i'm doing this is my controller
[HttpGet]
public ActionResult CreateModule()
{
var moduleTypes = _db.ModuleTypes.Select(moduleType => moduleType.TypeName).ToList();
var model = new CreateModule
{
TypeNames = moduleTypes.Select(m => new SelectListItem
{
Value = m,
Text = m,
})
};
return View(model);
}
and in view
<div class ="input-block-level">#Html.DropDownListFor(model => model.SelectedModuleTypeName, Model.TypeNames)</div>
That results to something like this
based upon my code, I'll get the TypeName from the view in my controller's post method.
How I can I change my code in order to access Id of the TypeName in controller?
Modify your Action:
public ActionResult CreateModule()
{
var moduleTypes = _db.ModuleTypes.Select(moduleType => new { TypeName = moduleType.TypeName, Id = moduleType.Id }).ToList();
var model = new CreateModule
{
TypeNames = moduleTypes.Select(m => new SelectListItem
{
Value = m.Id.ToString(),
Text = m.TypeName,
})
};
return View(model);
}
Select multiple items instead of single
var moduleTypes = _db.ModuleTypes
.Select(
moduleType => new {
Id = moduleType.Id
TypeName = moduleType.TypeName}
).ToList();
var model = new CreateModule
{
TypeNames = moduleTypes.Select(m => new SelectListItem
{
Value = m.Id.ToString(),
Text = m.TypeName,
})
};
The first statement is creating anonymous object using linq, and second statement is using it to create CreateModule
I want to make a Kendo TreeView that shows all nodes on first load. I'm using the Kendo 'Binding to remote data' sample but it doesn't work correctly. It shows just the first level and the id passed to the controller action is always null.
Please help me.
View code :
#(Html.Kendo().TreeView()
.Name("treeview")
.DataTextField("Title")
.ExpandAll(true)
.LoadOnDemand(false)
.DataSource(dataSource => dataSource
.Read(read => read.Action("Employees", "Follow").Data("addData"))))
function addData(data) {
return { id: data.id };
}
Controller code : (controller Follow)
public System.Web.Mvc.JsonResult Employees(int? id)
{
System.Collections.Generic.List<FollowType> List =
new System.Collections.Generic.List<FollowType>();
if (id.HasValue == true) {
List = FollowTypeList.FindAll(current => current.ParentId == id);
} else {
List = FollowTypeList.FindAll(current => current.ParentId == null);
}
System.Collections.Generic.List<Kendo.Mvc.UI.TreeViewItemModel> NodeList =
new System.Collections.Generic.List<Kendo.Mvc.UI.TreeViewItemModel>();
foreach (CommonData.Domain.FollowType item in List)
{
NodeList.Add(new Kendo.Mvc.UI.TreeViewItemModel() {
Id = item.Id.ToString(),
Text = item.Title,
HasChildren = FollowTypeList.Exists(c => c.Id == item.ParentId)
});
}
return Json(NodeList, System.Web.Mvc.JsonRequestBehavior.AllowGet);
}
I guess that in your javascript code, the id field of data should be Id (be careful to the capitalization) :
return { id : data.Id };
I am using this code in my view:
#(Html.Telerik().TreeView()
.Name("AjaxTreeView")
.BindTo(Model, (item, category) =>
{
// bind initial data - can be omitted if there is none
item.Text = category.Name;
item.Action("Details", "Categories", new { Id = category.Id });
item.Value = category.Id.ToString();
item.LoadOnDemand = category.NOChildren > 0;
})
.DataBinding(dataBinding => dataBinding
.Ajax().Select("_TreeViewAjaxLoading", "Categories")
)
)
It works fine (ajaxified expand and collapse). The action links work fine but only for the root nodes. My current controller that spews out JSON for the ajax load:
[Transaction]
[HttpPost]
public ActionResult _TreeViewAjaxLoading(TreeViewItem node)
{
int? ParentId = !string.IsNullOrEmpty(node.Value) ? (int?)Convert.ToInt32(node.Value) : null;
var nodes = from item in CategoryRepository.GetChildren(ParentId)
select new TreeViewItem
{
Text = item.Name,
Value = item.Id.ToString(),
LoadOnDemand = item.NOChildren > 0
};
return new JsonResult { Data = nodes };
}
does not set the action link. How can I set the action link here? Thanks.
Christian
This seems to do the trick:
[Transaction]
[HttpPost]
public ActionResult _TreeViewAjaxLoading(TreeViewItem node)
{
int? ParentId = !string.IsNullOrEmpty(node.Value) ? (int?)Convert.ToInt32(node.Value) : null;
UrlHelper u = new UrlHelper(this.ControllerContext.RequestContext);
var nodes = from item in CategoryRepository.GetChildren(ParentId)
select new TreeViewItem
{
Text = item.Name,
Value = item.Id.ToString(),
LoadOnDemand = item.NOChildren > 0,
Url = u.Action("Details", "Categories", new { Id = item.Id} )
};
return new JsonResult { Data = nodes };
}