Click here to Skip to main content
Click here to Skip to main content
Go to top

Build a custom MVC Tree Control by using jsTree

, 18 Sep 2014
Rate this:
Please Sign up or sign in to vote.
Let us learn how to build a simple MVC Tree Control by using jsTree (a jquery plugin, that provides interactive trees)

Introduction

In this article let us see how to build a simple custom MVC Tree control by making use of JsTree (http://www.jstree.com/). Here's in little about jsTree.

jsTree is a jquery plugin, that provides interactive trees. It is open source, free to use and is distributed under the MIT license. jsTree is easily extendable, themable and configurable, it supports HTML & JSON data sources and AJAX loading.

In this article, we will be making use of jsTree library in building a simple tree control in MVC.

Background

A very good understanding and working knowledge of ASP.NET MVC.

Using the code

Let us begin with the basics of using the jsTree and then later on we will deep dive in implementing the MVC Tree Control.

The first thing we will be doing is downloading the latest jsTree library from https://github.com/vakata/jstree/zipball/3.0.1

You will have to include the following style and scripts in the HTML document were you wish to render a jsTree. 

<link rel="stylesheet" href="~/Content/jsTreeTheams/style.min.css" />
<script src="~/Scripts/libs/jquery.js"></script>
<script src="~/Scripts/jstree.min.js"></script>

In the HTML document , just have a div with an id and inner HTML coded as below.

<div id="jstree_demo_div">
  <ul>
    <li>Root node 1</li>
    <li>Root node 2</li>
  </ul>
</div>

Here's how the tree gets rendered.

jsTreeSample-1

The next thing we need to do is creating a jsTree instance. This will create a jsTree and you can visually see a tree with the default styles applied to it.

$(function () { $('#jstree_demo_div').jstree(); });

Let us have a look into a sample code with a data-jstree attribute set on list items.

<li data-jstree='{"opened":true,"selected":true}'>Root
  <ul>
    <li data-jstree='{"disabled":true}'>Child</li>
    <li data-jstree='{"icon":"http://jstree.com/tree.png"}'>
      Child</li>
    <li data-jstree='{"icon":"glyphicon glyphicon-leaf"}'>
      Child</li>
  </ul>
</li>

jsTreeSample-2

In the above example, you can see some of the tree nodes are shown with opened, selected or disabled by setting the suitable properties for the same. Also one can set a custom icon to the jsTree node by setting the icon property of data-jstree. 

Let us now have look into building entities that is required as a part of the MVC Tree control.

Here's the code snippet for creating a TreeView entity. Let us consider the treeview is composed of Nodes which is nothing but a list of TreeNode. 

namespace MVCJsTree.Models
{
    public class TreeView
    {
        public TreeView()
        {
            this.Nodes = new List<TreeNode>();
        }

        public List<TreeNode> Nodes { get; set; }
    }
}

Below is the code snippet of a TreeNode entity. The TreeNode is composed of a list of NodeItem.

namespace MVCJsTree.Models
{
  public class TreeNode
  {
      public TreeNode()
      {
         ListItems = new List<INodeItem>();
      }

      public List<INodeItem> ListItems { get; set; }
  }
}

Here's the code snippet were you can see the implementation of INodeItem interface in ListItem entity. Note – The ListItem itself can have nodes which is nothing but a list of INodeItem. You could also optionally have an instance of ListItemAHref , DataJsTree entities.

public class ListItem : INodeItem
{
     public string Id { get; set; }
     public string Parent { get; set; }
     public string Class { get; set; }
     public string Text { get; set; }
     public ListItemAHref Href { get; set; }
     public DataJsTree DataJsTree { get; set; }
     public List<INodeItem> Nodes { get; set; }
      
     public ListItem(string text,
                     string id = "",
                     string parent = "#",
                     string className ="",
                     ListItemAHref ahref = null,
                     DataJsTree dataJsTree=null)
     {
          if (id != null)
             this.Id = id;

          this.Parent = parent;
          this.Text = text;
          this.Class = className;

          if (ahref != null)
             this.Href = ahref;
          else
             this.Href = new ListItemAHref();

          if (dataJsTree != null)
             this.DataJsTree = dataJsTree;
          else
             this.DataJsTree = new DataJsTree();

          Nodes = new List<INodeItem>();
     }
}

Here's the code snippet for DataJsTree, ListItemAHref entity.

public class DataJsTree
{
   public string Name { get; set; }
   public string Icon { get; set; }
   public bool Opened { get; set; }
   public bool Selected { get; set; }
   public bool Disabled { get; set; }
}

public class ListItemAHref
{
    public string Href { get; set; }
    public string Class { get; set; }

    public ListItemAHref(string href="#", string cssClass = "")
    {
       this.Href = href;
       this.Class = cssClass;
    }
}

Here's class diagram showing the entities which we will making use of in building a MVC Tree Control. 

DataModelClassDiagram

Below is the code snippet of HomeController were you can see the code for building a Treeview by making use of the above models TreeNode, ListItem, DataJsTree etc.

public class HomeController : Controller
{
     public ActionResult Index()
     {
          var treeView = new TreeView();
          var treeNode = new TreeNode();
          var rootNode = new ListItem("Root node 1", "node1");
          var dataJsTree = new DataJsTree();

          dataJsTree.Icon = "glyphicon glyphicon-leaf";
          dataJsTree.Opened = true;

          var fruitNode = new ListItem("Fruits", "fruitsNode", className: "jstree-open", dataJsTree: dataJsTree);
          var vegetableNode = new ListItem("Vegetables", "vegetablesNode", className: "");
          var appleNode = new ListItem("Apples", "applesNode", className: "");
          var broccoliNode = new ListItem("Broccoli", "broccoliNode", className: "");
          var carrotNode = new ListItem("Carrots", "carrotNode", className: "");
          var lettuceNode = new ListItem("Lettuces", "lettuceNode", className: "");
          var romaineNode = new ListItem("Romaine", "romaineNode", className: "");
          var iceBurgNode = new ListItem("IceBurg", "iceBurgNode", className: "");
          var butterheadNode = new ListItem("Butterhead", "butterheadNode", className: "");

          fruitNode.Nodes.Add(new ListItem("Oranges", "orange"));
          fruitNode.Nodes.Add(new ListItem("Pineapples", "pineapple"));

          appleNode.Nodes.Add(new ListItem("Macintosh", "Macintosh"));
          fruitNode.Nodes.Add(appleNode);

          lettuceNode.Nodes.Add(romaineNode);
          lettuceNode.Nodes.Add(iceBurgNode);
          lettuceNode.Nodes.Add(butterheadNode);

          vegetableNode.Nodes.Add(broccoliNode);
          vegetableNode.Nodes.Add(carrotNode);
          vegetableNode.Nodes.Add(lettuceNode);

          rootNode.Nodes.Add(fruitNode);
          rootNode.Nodes.Add(vegetableNode);

          treeNode.ListItems.Add(rootNode);
          treeView.Nodes.Add(treeNode);
   
          return View(treeView);
     }
}

Now let us take a look into the MVC view code snippet to render a jsTree. Here's the code snippet for the same. 

In the below code, we are making use of MVC functions and helpers in rendering the tree nodes.
Note – We are recursively iterating through the node items and build the HTML code which can be used to render a jsTree.

@functions 
{       
    private System.Text.StringBuilder sbMVCHtmlString = new System.Text.StringBuilder();
    private MvcHtmlString RenderListItem(MVCJsTree.Models.INodeItem treeItem)
    {
        foreach (var item in ((MVCJsTree.Models.INodeItem)treeItem).Nodes)
        {
            var listItem = ((MVCJsTree.Models.ListItem)item);
            var dataJsTree = listItem.DataJsTree;
            sbMVCHtmlString.AppendFormat("<li class='{0}' id='{1}' data-jstree='{6} \"opened\":{2}, \"selected\":{3}, \"disabled\":{4}, \"icon\":\"{5}\" {7}'> {8}",
                listItem.Class, listItem.Id, dataJsTree.Opened.ToString().ToLower(),
                dataJsTree.Selected.ToString().ToLower(), dataJsTree.Disabled.ToString().ToLower(), dataJsTree.Icon, "{", "}",
                listItem.Text);
            if( item.Nodes.Count > 0 )
            {
                sbMVCHtmlString.Append("<ul>");               
                RenderListItem(item);
                sbMVCHtmlString.Append("</ul>");  
            }
            sbMVCHtmlString.Append("</li>");
               
        }
        return new MvcHtmlString(sbMVCHtmlString.ToString());
    }        
}
           
@helper RenderTreeNodes(List<MVCJsTree.Models.TreeNode> treeNodes)
{
    var sbMVCHtmlString = new System.Text.StringBuilder();
        
    foreach (var treeNodeItem in treeNodes)
    {
        foreach (var listItem in treeNodeItem.ListItems)
        {
            sbMVCHtmlString.Append(RenderListItem(listItem));
        }
    }
        
    @Html.Raw(@sbMVCHtmlString.ToString())
}

The above code blocks works just fine but you will have to copy paste the functions and helpers in all the MVC views were you wish to render a jsTree. 

Now let us see how to build a MVC Tree control by reusing the above code blocks. Here's the code snippet for the same.

public static class JsTreeMVCControl
{
        private static System.Text.StringBuilder _htmlStringBuilder = new System.Text.StringBuilder();
        private static MvcHtmlString RenderListItem(MVCJsTree.Models.INodeItem treeItem)
        {
            foreach (var item in ((MVCJsTree.Models.INodeItem)treeItem).Nodes)
            {
                var listItem = ((MVCJsTree.Models.ListItem)item);
                var dataJsTree = listItem.DataJsTree;
                
                _htmlStringBuilder.AppendFormat("<li class='{0}' id='{1}' data-jstree='{6} \"opened\":{2}, \"selected\":{3}, \"disabled\":{4}, \"icon\":\"{5}\" {7}'> {8}",
                    listItem.Class, listItem.Id, dataJsTree.Opened.ToString().ToLower(),
                    dataJsTree.Selected.ToString().ToLower(), dataJsTree.Disabled.ToString().ToLower(),
                    dataJsTree.Icon, "{", "}", listItem.Text);

                if (item.Nodes.Count > 0)
                {
                    _htmlStringBuilder.Append("<ul>");
                    RenderListItem(item);
                    _htmlStringBuilder.Append("</ul>");
                }

                _htmlStringBuilder.Append("</li>");
            }

            return new MvcHtmlString(_htmlStringBuilder.ToString());
        }

        public static MvcHtmlString RenderJsTreeNodes(this HtmlHelper html, 
                                                      List<MVCJsTree.Models.TreeNode> treeNodes)
        {
            _htmlStringBuilder = new System.Text.StringBuilder();

            var stringBuilder = new System.Text.StringBuilder();

            foreach (var treeNodeItem in treeNodes)
            {
                foreach (var listItem in treeNodeItem.ListItems)
                {
                    stringBuilder.Append(RenderListItem(listItem));
                }
            }

            return new MvcHtmlString(stringBuilder.ToString());
        }
}

Here's the code snippet shows how to use a custom helper extension to render a jsTree nodes.

@model MVCJsTree.Models.TreeView
@using MVCJsTree.Controls;

@{
    ViewBag.Title = "Index";
}

<link rel="stylesheet" href="~/Content/jsTreeTheams/style.min.css" />
<script src="~/Scripts/libs/jquery.js"></script>
<script src="~/Scripts/jstree.min.js"></script>

<div id="jstree_demo_div">
    <ul>
        @Html.RenderJsTreeNodes(Model.Nodes)
    </ul>
</div>

<script type="text/javascript">

    $('#jstree_demo_div').jstree();

</script>

DemoMainScreen

Points of Interest

While working with this code sample, I personally learnt a lot in building a simple and reusable custom MVC control. We can do a lot with this control. As of now, the control had a bare minimum functionality but you can easily extend the same as per your requirements.

History

Version 1.0 - Created a basic MVC Tree Control with a bare minimum features - 06/16/2014

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ranjan.D
Web Developer
United States United States
Profile
 
Around 9 years of professional software development experience in analysis, design, development, testing and implementation of enterprise web applications for healthcare domain with good exposure to object-oriented design, software architectures, design patterns, test-driven development and agile practices.
 
In Brief
 
Analyse and create High Level , Detailed Design documents.
Use UML Modelling and create Use Cases , Class Diagram , Component Model , Deployment Diagram, Sequence Diagram in HLD.
 
Area of Working : Dedicated to Microsoft .NET Technologies
Experience with : C# , J2EE , J2ME, Windows Phone 8, Windows Store App
Proficient in: C# , XML , XHTML, XML, HTML5, Javascript, Jquery, CSS, SQL, LINQ, EF
 
Software Development
 
Database: Microsoft SQL Server, FoxPro
Development Frameworks: Microsoft .NET 1.1, 2.0, 3.5, 4.5
UI: Windows Forms, Windows Presentation Foundation, ASP.NET Web Forms and ASP.NET MVC3, MVC4
Coding: WinForm , Web Development, Windows Phone, WinRT Programming, WCF, WebAPI
 
Healthcare Domain Experience
 
CCD, CCR, QRDA, HIE, HL7 V3, Healthcare Interoperability
 
Others:
 
TTD, BDD
 
Education
 
B.E (Computer Science)
 
CodeProject Contest So Far:
 
1. Windows Azure Developer Contest - HealthReunion - A Windows Azure based healthcare product , link - http://www.codeproject.com/Articles/582535/HealthReunion-A-Windows-Azure-based-healthcare-pro
 
2. DnB Developer Contest - DNB Business Lookup and Analytics , link - http://www.codeproject.com/Articles/618344/DNB-Business-Lookup-and-Analytics
 
3. Intel Ultrabook Contest - Journey from development, code signing to publishing my App to Intel AppUp , link - http://www.codeproject.com/Articles/517482/Journey-from-development-code-signing-to-publishin
 
4. Intel App Innovation Contest 2013 - eHealthCare - http://www.codeproject.com/Articles/635815/eHealthCare
 
5. Grand Prize Winner of CodeProject HTML5 &CSS3 Article Content 2014

Comments and Discussions

 
QuestionDuplication Issue PinmemberMember 1109030017hrs 48mins ago 
AnswerRe: Duplication Issue PinmvpRanjan.D9hrs 33mins ago 
GeneralExcellent work. One issue found PinmemberMember 452269312-Sep-14 4:49 
GeneralRe: Excellent work. One issue found PinmvpRanjan.D12-Sep-14 5:48 
GeneralRe: Excellent work. One issue found PinmvpRanjan.D9hrs 32mins ago 
QuestionExcellent PinmemberMember 43662205-Sep-14 1:54 
AnswerRe: Excellent PinmvpRanjan.D5-Sep-14 3:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 18 Sep 2014
Article Copyright 2014 by Ranjan.D
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid