Lazy Loading TreeView Sample with ASP.NET MVC and jqTree
I’ve been looking for a lightweight TreeView library to use with ASP.NET MVC, and I think I’ve found my “weapon of choice” – jqTree.
The code is available on https://github.com/mbraak/jqTree and the author mbraak (Marco Braak) is very active in the “issues” section answering questions from users.
The package is not available on Nuget at the moment though, but it’s easy enough to download and set up manually.
Download and unzip the code from Github, copy the files jqtree.css and jqtree-circle.png to your /Content folder, and copy the tree.jquery.js file to your /Scripts folder. Then open up your /App_Start/BundlesConfig.cs file and add the files to your bundles, something like this:
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( "~/Scripts/bootstrap.js", "~/Scripts/tree.jquery.js", "~/Scripts/respond.js")); bundles.Add(new StyleBundle("~/Content/css").Include( "~/Content/bootstrap.css", "~/Content/jqtree.css", "~/Content/font-awesome.min.css", "~/Content/site.css"));
Add this viewmodel to hold the treeview node data:
public class Node { public string label { get; set; } public string id { get; set; } public bool load_on_demand { get; set; } public Node(string label, string id, bool loadOnDemand = true) { this.label = label; this.id = id; this.load_on_demand = loadOnDemand; } }
Then create a controller method in HomeController.cs which will be called on-demand/lazily by the TreeView control in your HTML-view. My action is called /Home/Nodes and takes and optional “node” parameter which holds the id of the treeview-node being “expanded”. This is some simple test-code using the local computer folder structure on the D-drive just to try it out. If it’s a folder I’m passing “true” to the load_on_demand property of the jqTree javascript model:
public ActionResult Nodes(string node) { Debug.WriteLine("id=" + node); var list = new List<Node>(); if (node == null) { var items = Directory.GetFileSystemEntries("D:/"); foreach (var item in items) { list.Add(new Node(Path.GetFileName(item), item, Directory.Exists(item))); } } else { var items = Directory.GetFileSystemEntries(node); foreach (var item in items) { list.Add(new Node(Path.GetFileName(item), item, Directory.Exists(item))); } } return Json(list, JsonRequestBehavior.AllowGet); }
In your Razor HTML-view, the base for the TreeView control is a simple <div> tag, with an data-url attribute pointing at the method it should call to get data:
<div id="tree1" data-url="/home/nodes"></div>
and finally some javascript/jquery to initialize the TreeView and add some handling, this code loads the treeview, sets the icons I would like to have (from font-awesome) and adds a click-handler which just writes out the selected node name to the console.
@section scripts { <script language="javascript" type="text/javascript"> $(function () { $('#tree1').tree({ closedIcon: $('<i class="fa fa-plus"></i>'), openedIcon: $('<i class="fa fa-minus"></i>'), dragAndDrop: false, selectable: false }); // bind 'tree.click' event $('#tree1').bind( 'tree.click', function (event) { // The clicked node is 'event.node' var node = event.node; console.log('clicked ' + node.name ); } ); }); </script> }
This is all you need to do, and it’s possible (and quite easy too) to modify the look of the tree in the view, have your own icons and such. Ask questions in the “issues” section of the project and I’m sure you’ll get your answers - https://github.com/mbraak/jqTree/issues
Thanks to mbraak for cool stuff, me likes