<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<TreeViewCRUD.Models.Category>>" %>
<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.Telerik().TreeView()
.Name("TreeView")
.BindTo(Model, mappings =>
{
mappings.For<TreeViewCRUD.Models.Category>(binding => binding
.ItemDataBound((item, category) =>
{
item.Text = category.CategoryName;
item.Value = category.CategoryID.ToString();
})
.Children(category => category.Products));
mappings.For<TreeViewCRUD.Models.Product>(binding => binding
.ItemDataBound((item, product) =>
{
item.Text = product.ProductName;
item.Value = product.ProductID.ToString();
}));
})
.ClientEvents(events => events.OnLoad("onLoad"))
%>
<script type="text/javascript">
function onLoad() {
// subscribe to the contextmenu event to show a contet menu
$('.t-in', this).live('contextmenu', function(e) {
// prevent the browser context menu from opening
e.preventDefault();
// the node for which the 'contextmenu' event has fired
var $node = $(this).closest('.t-item');
// default "slide" effect settings
var fx = $.telerik.fx.slide.defaults();
// context menu definition - markup and event handling
var $contextMenu =
$('<div class="t-animation-container" id="contextMenu">' +
'<ul class="t-widget t-group t-menu t-menu-vertical" style="display:none">' +
'<li class="t-item"><a href="#" class="t-link">Edit</a></li>' +
'<li class="t-item"><a href="#" class="t-link">Delete</a></li>' +
'</ul>' +
'</div>')
.css( //positioning of the menu
{
position: 'absolute',
left: e.pageX, // x coordinate of the mouse
top: e.pageY // y coordinate of the mouse
})
.appendTo(document.body)
.find('.t-item') // select the menu items
.mouseenter(function() {
// hover effect
$(this).addClass('t-state-hover');
})
.mouseleave(function() {
// remove the hover effect
$(this).removeClass('t-state-hover');
})
.click(function(e) {
e.preventDefault();
// dispatch the click
onItemClick($(this), $node);
})
.end();
// show the menu with animation
$.telerik.fx.play(fx, $contextMenu.find('.t-group'), { direction: 'bottom' });
// handle globally the click event in order to hide the context menu
$(document).click(function(e) {
// if clicked inside the editing textbox - discard
if ($(e.target).is('#TreeView :text'))
return;
// remove any textboxes from the treeview and update the node if needed
$('#TreeView :text').each(function() {
var $textBox = $(this);
var newText = $textBox.val();
var oldText = $textBox.data('text');
// the node to which the textbox belongs to
var $node = $textBox.closest('.t-item');
// remove the textbox from the node
$textBox.replaceWith($('<span class="t-in" />').html(newText));
// if the text changed update the node
if (newText != oldText) {
onEdit($node);
}
});
// hide the context menu and remove it from DOM
$.telerik.fx.rewind(fx, $contextMenu.find('.t-group'), { direction: 'bottom' }, function() {
$contextMenu.remove();
});
});
});
}
function onItemClick($item, $node) {
var treeView = $('#TreeView').data('tTreeView');
var nodeText = treeView.getItemText($node);
var menuItemText = $item.text();
if (menuItemText == "Edit") {
// replace the node contents with a textbox
setTimeout(function() {
$node.find('.t-in:first')
.replaceWith($('<input type="text" />')
.val(nodeText)
.data('text', nodeText)
.keydown(function(e) {
if (e.keyCode == 13) {
// handle enter key - edit the node
var newText = $(this).val();
// remove the textbox from the node
$(this).replaceWith($('<span class="t-in"/>').html(newText));
if (newText != nodeText) {
// if the text changed update the node
onEdit($node);
}
} else if (e.keyCode == 27) {
// handle escape key - cancel editing
// remove the textbox from the node
$(this).replaceWith($('<span class="t-in"/>').html(nodeText));
}
}))
}, 0);
} else if (menuItemText == "Delete") {
//delete the node
onDelete($node);
}
}
function onEdit($node) {
var treeView = $('#TreeView').data('tTreeView');
// post to HomeController.EditNode using jQuery
$.post('<%= Url.Action("EditNode", "Home") %>',
{
level: $node.parents('.t-item').length, // node level required to determine whether this is a Category or a Product
id: treeView.getItemValue($node),
text: treeView.getItemText($node)
}
);
}
function onDelete($node) {
var treeView = $('#TreeView').data('tTreeView');
if (confirm('Are you sure you want to delete this node?')) {
// post to HomeController.DeleteNode using jQuery
$.post('<%= Url.Action("DeleteNode", "Home") %>',
{
level: $node.parents('.t-item').length,
id: treeView.getItemValue($node),
});
$node.remove();
}
}
</script>
</asp:Content>
controller
using System.Linq;
using System.Web.Mvc;
using TreeViewCRUD.Models;
namespace TreeViewCRUD.Controllers
{
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new NorthwindDataContext().Categories);
}
public ActionResult EditNode(int level, int id, string text)
{
var northwind = new NorthwindDataContext();
northwind.ObjectTrackingEnabled = true;
if (level == 0)
{
var category = northwind.Categories.FirstOrDefault(c => c.CategoryID == id);
if (category != null)
{
category.CategoryName = text;
}
}
else
{
var product = northwind.Products.FirstOrDefault(p => p.ProductID == id);
if (product != null)
{
product.ProductName = text;
}
}
northwind.SubmitChanges();
return new EmptyResult();
}
public ActionResult DeleteNode(int level, int id)
{
var northwind = new NorthwindDataContext();
northwind.ObjectTrackingEnabled = true;
if (level == 0)
{
var category = northwind.Categories.FirstOrDefault(c => c.CategoryID == id);
if (category != null)
{
foreach (var product in category.Products)
{
northwind.Products.DeleteOnSubmit(product);
}
northwind.Categories.DeleteOnSubmit(category);
}
}
else
{
var product = northwind.Products.FirstOrDefault(p => p.ProductID == id);
if (product != null)
{
northwind.Products.DeleteOnSubmit(product);
}
}
northwind.SubmitChanges();
return new EmptyResult();
}
}
}