
Our company is about to start developing a ASP.NET web application using VS 2010 with MVC 2.0. We are planning on using a tree view for navigation with right-click features for basic actions.
I have had a brief look at your ASP.NET MVC package and it seems to have a limited set of features compared to the ASP.NET Ajax version. Is there any (simple) way of adding right-click/context menus to the MVC TreeView items?
Kind regards,
Morten Felumb
20 Answers, 1 is accepted
Indeed currently there is no easy way to implement context menus for the treeview. A possible workaround is to use any of the available jquery context menu plugins.
Regards,
Atanas Korchev
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.

Have you achieved the functionality to show context menu on Tree Items.
If yes Pleasei let me know, how u have achieved it.
I will be very thankful to you.

We decided to use ExtJs for our project, so we did not finish a Telerik / jquery implementation of context menus.
Regards,
Morten Felumb



Yes please; It will be helpful to understand how you implemented it, as it is useful. Thanks.
Regards,
Espen

I am developing using mvc. I used the context menu plugin from this site : http://abeautifulsite.net/blog/2008/09/jquery-context-menu-plugin/. Download it and include it in your page:
Give this a go and let me know how it goes or where you need me to clarify mate.
<%= Html.Telerik().TreeView()
.Name("TreeView")
.ClientEvents(events => events
.OnDataBinding("onDataBinding").OnSelect("onSelect")
)
%>
Script:
function onDataBinding(e) {
var treeview = $('#TreeView').data('tTreeView');
var jsonObject;
jsonObject = <%= Model.type%>;
treeview.bindTo(jsonObject);
// Show menu when a list item is clicked
$(".t-treeview span.t-in").contextMenu({
menu: 'myMenu'
}, function (action, el, pos) {
switch(action)
{
case 'create':
$("#divnewfolder").dialog( "open" );
break;
case 'edit':
$("#divrenamefolder").dialog( "open" );
break;
case 'delete':
$("#divdelete").dialog( "open" );
break;
}
});
$(".t-treeview span.t-in").mousedown(function(e){
//i check if it is a right click
if (e.button == 2) {
$('#hfrightclick').val($(this).siblings('input.t-input').val());
}
});
}

The following code seems to be working for me: Check the OnDataBound(). Also check-out the lat reply at this forum for positioning the context-menu. http://plugins.jquery.com/content/contextmenu-pops-wrong-place
<%= Html.Telerik().TreeView()
.Name("GroupsTreeView")
.DragAndDrop(true)
.ClientEvents(events => events
.OnDataBound("onDataBound"))
.BindTo(Model, (item, group) =>
{
// bind initial data - can be omitted if there is none
item.Text = group.GroupName;
item.Value = group.GroupID.ToString();
item.LoadOnDemand = true;
})
.DataBinding(dataBinding => dataBinding
.Ajax().Select("AjaxLoading", "Groups")
)
%>
</div>
<ul id="myMenu" class="contextMenu">
<li class="edit"><a href="#edit">Edit</a> </li>
<li class="cut separator"><a href="#cut">Cut</a> </li>
<li class="copy"><a href="#copy">Copy</a> </li>
<li class="paste"><a href="#paste">Paste</a> </li>
<li class="delete"><a href="#delete">Delete</a> </li>
<li class="quit separator"><a href="#quit">Quit</a> </li>
</ul>
<script type="text/javascript">
function onDataBound(e) {
BindTreeViewContextMenu();
}
function BindTreeViewContextMenu() {
// Show menu when a list item is clicked
$("#GroupsTreeView .t-in").each(function () {
$(this).contextMenu({
menu: 'myMenu'
}, function (action, el, pos) {
alert(
'Action: ' + action + '\n\n' +
'Element text: ' + $(el).text() + '\n\n' +
'X: ' + pos.x + ' Y: ' + pos.y + ' (relative to element)\n\n' +
'X: ' + pos.docX + ' Y: ' + pos.docY + ' (relative to document)'
);
});
});
}
</script>

Donna

$("#TreeView .t-in").each(function () {
$(this).contextMenu({
menu: 'myMenu'
}, function (action, el, pos) {
var currentValueId = $(el).next('.t-input').val();
switch (action) {
case 'add': OnAddWindowLoad(currentGroupId); break;
case 'edit': OnEditWindowLoad(currentGroupId); break;
....etc
}
});
});
hth,



The generated HTML looks like this:
<div class="t-widget t-treeview t-reset" id="OutlineTree"><ul class="t-group t-treeview-lines"><li class="t-item t-first"><div class="t-top"><span class="t-in"><img alt="Included in Designator" class="t-image" src="/ReviewContentManager/Content/Common/Images/Icons/accept.png" style="width: 16px; height: 16px;" />
Z Z Top
<button class="grid-row-action-button right" name="rowActionMenu_7c09bfbf-7de8-4320-aae4-f6814efcba51" style="display: none" onclick="Grid_showRowAction(event, '7c09bfbf-7de8-4320-aae4-f6814efcba51');">▼</button></span><input class="t-input" name="itemValue" type="hidden" value="7c09bfbf-7de8-4320-aae4-f6814efcba51" /></div>
So the hidden element is there. My function is as follows where currentValueId is coming up undefined:
function tv_OnSelect(e) {
var currentValueId = $(e).next('.t-input').val();
jQuery('[id^=rowActionMenu], .grid-row-action-button').hide();
document.getElementsByName('rowActionMenu_' + currentValueId).style.visibility = "visible";
}
Thanks!

function OnTreeNodeSelect(e) {
var selectedItem = $(e.item).closest('.t-item');
...
.
.
}


The context menu as suggested works perfectly.
Except now, my "drag & drop" all of a sudden stopped working. it's the $(document).ready.... that kills my "drag & drop".
When I don't do the $(document).ready part my treeview is rendered as
<div class="t-widget t-treeview t-reset" id="TreeView" jQuery164022326143430375406="2">
when I do use $(document).ready, My tree is rendered as
<div class="t-widget t-treeview t-reset" id="TreeView" jQuery16406377481044573372="82">
I wonder what's going on with that? any suggestions?
here's a simplified version of my code:
@(Html.Telerik().TreeView()
.Name("TreeView")
.DragAndDrop(settings => settings.Enabled(true))
.ClientEvents(e=>e
.OnSelect("trvItem_Selected")
.OnNodeDrop("HandleNodeDrop")
)
.BindTo
(
Model.RootJobs.Values, mappings =>
{
mappings.For<Monitor>(binding => binding
.ItemDataBound((item, job) =>
{
item.Text = job.JobName;
item.HtmlAttributes.Add("id", job.JobId);
item.ImageHtmlAttributes.Add("id", job.JobId);
})
.Children(childJob => childJob.Children));
}
)
)
<ul id="myMenu" class="contextMenu">
<li class="add"><a href="#add">Add New</a></li>
<li class="edit"><a href="#edit">Edit</a></li>
<li class="delete"><a href="#delete">Delete</a></li>
</ul>
<!-- ADD -->
@using (Ajax.BeginForm("AddValidator", "Monitor", new AjaxOptions(){ HttpMethod = "Post", InsertionMode = InsertionMode.Replace }, new { id = "frmAddJobValidator"}))
{
<input type="hidden" name='parentJobId' value='' />
}
<!-- EDIT -->
@using (Ajax.BeginForm("EditValidator", "Monitor", new AjaxOptions(){ HttpMethod = "Post", InsertionMode = InsertionMode.Replace }, new { id = "frmEditJobValidator"}))
{
<input type="hidden" name='jobId' value='' />
}
<!-- DELETE -->
@using (Ajax.BeginForm("DeleteValidator", "Monitor", new AjaxOptions(){ HttpMethod = "Post", InsertionMode = InsertionMode.Replace }, new { id = "frmDeleteValidator" }))
{
<input type="hidden" name='jobId' value='' />
}
<!-- DRAG & DROP -->
@using (Ajax.BeginForm("DragAndDrop", "Monitor", new AjaxOptions(){ HttpMethod = "Post",InsertionMode = InsertionMode.Replace }, new{ id = "frmDragAndDrop" }))
{
<input type="hidden" name='draggedItemId' value='' />
<input type="hidden" name='targetItemId' value='' />
}
<script type="text/javascript">
$(document).ready(function ()
{
$("#TreeView li").each(function ()
{
$(this).contextMenu(
{
menu: 'myMenu'
},
function (action, el, pos)
{
var currentValueId = $(el).attr('id');
switch (action)
{
case 'add': AddValidator(currentValueId); break;
case 'edit': EditValidator(currentValueId); break;
case 'delete': DeleteValidator(currentValueId); break;
}
});
});
});
</script>

Context menu and drag drop funcion great separately.
If I enable context menu, however, drag and drop functionality stops.

http://stackoverflow.com/questions/6788566/jquery-context-menu-clashes-with-jquery-draggable
you should change the context menu source like this:
jQuery(this).mousedown( function(e) {
var evt = e;
if (e.button != 2) return; //Added to make this compatible with draggable
evt.stopPropagation();
jQuery(this).mouseup( function(e) {
e.stopPropagation();
var srcElement = jQuery(this);

Just to be clear, the code changes suggested here should be done in the actual "SOURCE" code of "jquery.contextMenu.js". Also if you're doing a ctrl+f to find where to make the change, note your version may have jQuery(this).mouseup(..., or simply $(this).mouseup(function...
Anyways, that finalized the work.
Thanks!!!

.Name("TreeView")
.ClientEvents(events => events
.OnDataBinding("onDataBinding").OnSelect("onSelect")
)
%>
Script:
function onDataBinding(e) {
var treeview = $('#TreeView').data('tTreeView');
var jsonObject;
jsonObject = <%= Model.type%>;
treeview.bindTo(jsonObject);
How to use this: "<%= Model.type%>"; on Razor?