The first article tree's definition is as follows:
<div id="TreeViewArticle">
<%
= Html.Telerik().TreeView()
.Name(
"TreeView")
.DragAndDrop(settings => settings
.DropTargets(
".drop-container")
)
.ClientEvents(events => events
.OnNodeDrop(
"onNodeDrop")
.OnSelect(
"onSelect")
)
.BindTo(Model, (item, Article) =>
{
// bind initial data - can be omitted if there is none
item.Text = Article.Name;
item.Value = Article.ID.ToString();
item.LoadOnDemand =
true;
})
.DataBinding(dataBinding =>
{
dataBinding.Ajax()
.Enabled(
true)
.Select(
"LoadArticlesOnDemand", "Home");
})
%>
</div>
The second tree, which will contain the documents associated with the selected article of the first tree is as follows:
<%
= Html.Telerik().TreeView()
.Name(
"TreeViewRelArticle")
.DragAndDrop(settings => settings
.DropTargets(
".drop-container")
)
.ClientEvents(events => events
.OnNodeDrop(
"onNodeDropRel")
// .OnSelect("onSelectRel")
)
.BindTo(Model, (item, Article) =>
{
// bind initial data - can be omitted if there is none
item.Text =
"Related Documents";
item.Value =
"0";
item.LoadOnDemand =
true;
})
.DataBinding(dataBinding =>
{
dataBinding.Ajax()
.Enabled(
true)
.Select(
"LoadRelArticlesOnDemand", "Home");
})
%>
The problem is that the LoadRelArticlesOnDemand method is only called to load the second tree when a node is expanded on the second tree by clicking on it's expansion icon. The data needs to change after selecting a node on the first tree.
Thanks in advance
10 Answers, 1 is accepted
Indeed, the Ajax data-binding isn't suitable for this scenario. You should do the following:
- Attach an OnSelect event handler to the first TreeView.
- In the OnSelect handler, make an Ajax request using jQuery to get the related documents for the selected node
- Populate the second TreeView using client-side data-binding.
Sincerely yours,
Alex Gyoshev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
Hi Alex
Thank you for your prompt reply. Can you tell me what needs to be coded in the first tree's OnSelect method in order for the onbinding method to be called? My onbinding method is not being called. My two tree definitions are as follows:
<%
= Html.Telerik().TreeView()
.Name(
"TreeView")
.DragAndDrop(settings => settings
.DropTargets(
".drop-container")
)
.ClientEvents(events => events
.OnNodeDrop(
"onNodeDrop")
.OnSelect(
"onSelect")
)
.BindTo(Model, (item, employee) =>
{
// bind initial data - can be omitted if there is none
item.Text = employee.FirstName + " " + employee.LastName;
item.Value = employee.EmployeeID.ToString();
item.LoadOnDemand =
true; // employee.Count == 0;
})
.DataBinding(dataBinding =>
{
dataBinding.Ajax()
.Enabled(
true)
.Select(
"_AjaxLoading", "Home");
})
%>
<%= Html.Telerik().TreeView()
.Name("TreeView2")
.Items(item =>
{
item.Add()
.Text(
"Related Items") .Expanded(true)
.LoadOnDemand(
true);
})
.ClientEvents(events => events
.OnSelect(
"onSelect2")
.OnDataBinding(
"onDataBinding")
)
%>
My onSelect and onbinding methods are as follows:
< script type="text/javascript">
function onSelect(e) {
var item = $(e.item);
var node = $(e.item).closest('.t-item').find(':input[name*="Value"]').val();
alert(
"Clicked on employee: " + $(e.item).closest('.t-item').find(':input[name*="Value"]').val());
$.getJSON(
"/Home/GetRelatedItems", { node: node }, function(result) {
alert(
"Related Items: Text = " + result[0].Text + " Value = " + result[0].Value);
});
}
function onDataBinding(e) {
alert(
"onDataBinding says Hi"); //Control does not go here!
var treeview = $('#TreeView2').data('tTreeView');
var jsonObject = [{ Value: "1", Text: "Product 1", Expanded: true, Items: [{ Value: "4", Text: "Product 4" }, { Value: "5", Text: "Product 5" }, { Value: "6", Text: "Product 6" }, { Value: "7", Text: "Product 7"}] }, { Value: "2", Text: "Product 2 (unavailable)", Enabled: false }, { Value: "3", Text: "Product 3"}];
treeview.bindTo(jsonObject);
}
function onSelect2() {
alert(
"ok");
}
</
script>
If I understand your answer correctly, the onSelect method must get the Json data from the controller and save it somewhere so that the onbinding function can use it to bind to the second tree. But what causes the onbinding method to be called?
Thanks for your help,
Sincerely,
Eugene
You can find attached a sample application that demonstrates the previously described approach. Please note that it uses a newer version of the assembly, which addresses a bug with the client-side binding of the TreeView. All you need to do is to wire the onSelect handler to make an AJAX call instead of generating the items.
All the best,
Alex Gyoshev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
I follow your example for the related trees and the code works for populating the related tree with a list of items. However, when I try to add children to the related tree, the tree disappears. Can you please tell me what is wrong with my code? Also, how does the format code block for code snippets work? If I simply paste code in this window, which I have done again, it looks terrible and is hard to read so I apologize for it's appearance.
Thanks,
Eugene
public ActionResult GetRelatedItems(string node)
{
TreeViewItemModel tvItem0, tvItem;
List<Employee> viewdata = (List<Employee>)Session["viewdata"];
List<Employee> viewdata2 = (List<Employee>)Session["viewdata2"];
// Root node
tvItem0 =
new TreeViewItemModel();
tvItem0.Text =
"Related Items";
tvItem0.Value =
"0";
tvItem0.Expanded =
true;
tvItem0.LoadOnDemand =
false;
tvItem0.Enabled =
true;
switch (node)
{
case null:
tvItem =
new TreeViewItemModel();
tvItem.Text =
"related items";
tvItem.Value =
"75";
tvItem.Expanded =
false;
tvItem.LoadOnDemand =
false;
tvItem.Enabled =
true;
tvItem0.Items.Add(tvItem);
break;
case "100":
foreach (Company company in viewdata[0].arrCompanies)
{
tvItem =
new TreeViewItemModel();
tvItem.Text = company.CompanyName;
tvItem.Value = company.CompanyID;
tvItem.Expanded =
false;
tvItem.LoadOnDemand =
false;
tvItem.Enabled =
true;
tvItem0.Items.Add(tvItem);
}
break;
case "90":
foreach (Company company in viewdata2[0].arrCompanies)
{
tvItem =
new TreeViewItemModel();
tvItem.Text = company.CompanyName;
tvItem.Value = company.CompanyID;
tvItem.Expanded =
false;
tvItem.LoadOnDemand =
false;
tvItem.Enabled =
true;
tvItem0.Items.Add(tvItem);
}
break;
case "75":
foreach (Company company in viewdata2[1].arrCompanies)
{
tvItem =
new TreeViewItemModel();
tvItem.Text = company.CompanyName;
tvItem.Value = company.CompanyID;
tvItem.Expanded =
false;
tvItem.LoadOnDemand =
false;
tvItem.Enabled =
true;
tvItem0.Items.Add(tvItem);
}
break;
}
return new JsonResult { Data = tvItem0 }; // What is wrong with this json result?
function onSelect(e) {
var item = $(e.item);
var node = $(e.item).closest('.t-item').find(':input[name*="Value"]').val();
$.getJSON(
"/Home/GetRelatedItems", { node: node }, function(result) {
$('#TreeView2').data('tTreeView').bindTo(result);
});
<%
= Html.Telerik().TreeView()
.Name(
"TreeView")
)
.ClientEvents(events => events
.OnSelect("onSelect")
)
.BindTo(Model, (item, employee) =>
{
// bind initial data - can be omitted if there is none
item.Text = employee.FirstName +
" " + employee.LastName;
item.Value = employee.EmployeeID.ToString();
item.LoadOnDemand =
true; // employee.Count == 0;
})
.DataBinding(dataBinding =>
{
dataBinding.Ajax()
.Enabled(
true)
.Select(
"_AjaxLoading", "Home");
})
%>
<%
= Html.Telerik().TreeView()
.Name(
"TreeView2")
.Items(item =>
{
item.Add()
.Text(
"Related Items");
})
%>
I think that the problem lies in the JavaScript, namely
$('#TreeView2').data('tTreeView').bindTo(result);
should be
$('#TreeView2').data('tTreeView').bindTo([result]);
because the TreeView wants an array of items that it can bind to.
In order to illustrate this, I've adjusted the sample application so that it uses a JSON call to load the related items in the second TreeView.
I understand that the whole client-side binding is a bit frustrating, and I'll try to improve it for the next release.
Sincerely yours,
Alex Gyoshev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
Thank you so much for your prompt and correct answer.
Best Regards,
Eugene
Below are the pretinent code snippets:
Javascript: function getUserGroupsForTaskGroup(e) { var taskGroupTree = $('#WTGroupNames').data('tTreeView'); var selectedValue = taskGroupTree.getItemValue(e.item); var userGroupTree = $('#UGsForTGs');
$.post('<%= Url.Action("GetUserGroupsForTaskGroup", "WebTask") %>', // The url of the /Home/Grid action method
{
id: selectedValue
}, // arguments which need to be passed to the Grid action method
function (result, textStatus) { //JavaScript callback executed when the ajax request finishes
userGroupTree.data('tTreeView').bindTo([result]); // update the DIV which contains the grid
},
"json"
);
}
The 2 treeviews:
<%= Html.Telerik().TreeView().Name("WTGroupNames").ShowCheckBox(True).HtmlAttributes(New With {.style = "width:250px; height:550px;"}) _
.ClientEvents(Function(evt) evt.OnSelect("getUserGroupsForTaskGroup")) _
.BindTo(CType(Model.wtGoupNames, IEnumerable(Of SelectListItem)),
Sub(mappings)
mappings.For(Of SelectListItem)(
Sub(binding)
binding _
.ItemDataBound(
Sub(item, linkGroup)
item.Text = linkGroup.Text
item.Value = linkGroup.Value
item.LoadOnDemand = True
End Sub)
End Sub)
End Sub) _
.DataBinding(Function(dataBinding) dataBinding.Ajax().Select("GetTasksForGroup", "WebTask"))
%>
<div id="usergroupsfortaskgroups">
<%= Html.Telerik().TreeView().Name("UGsForTGs").HtmlAttributes(New With {.style = "width:250px; height:550px;"}) _
.Items(Function(treeview) treeview.Add().Text("Related user groups")) _
.DataBinding(Function(dataBinding) dataBinding.Ajax().Select("GetUsersForUserGroups", "WebTask"))
%>
</div>
Controller:
<AcceptVerbs(HttpVerbs.Post)> _
Public Function GetUserGroupsForTaskGroup(ByVal id As Integer) As JsonResult
Dim gmcPermissions As New GMCPermissions
Dim userGroups As List(Of WebUserGroupName) = gmcPermissions.GetUserGroupNamesForTaskGroupNameKey(id)
Dim nodes As New List(Of TreeViewItem)
For Each userGrp In userGroups
nodes.Add(New TreeViewItem With {.Text = userGrp.UserGroupName, .Value = userGrp.UserGroupNameKey, .LoadOnDemand = True})
Next
Return New JsonResult() With {.Data = nodes}
End Function
Thank you,
Donna
Thank you for sending the relevant code. The only potential problem I can spot is that you're wrapping the response in an array:
userGroupTree.data('tTreeView').bindTo([result]);Try binding to the result itself:
userGroupTree.data('tTreeView').bindTo(result);If this doesn't help, can you please send us a sample project that we can debug locally? Thank you.
Best regards,
Tsvetomir Tsonev
the Telerik team
Donna