Introduction
This article introduces how to create a parent / child tree view in ASP.NET MVC using Bootstrap and jQuery. It is a practical approach so we create an example in which we will create a parent object. The parent object will have associated child objects.
Using the Code
We create two classes, one is AuthorViewModel and another is BookViewModel. AuthorViewModel is the main class that has an association with the BookViewModel class. In other words each AuthorViewModel class object has a list of BookViewModel class objects. The following is the code snippet for the BookViewModel class.
- namespace TreeView.Models
- {
- public class BookViewModel
- {
- public long Id
- {
- get;
- set;
- }
- public string Title
- {
- get;
- set;
- }
- public bool IsWritten
- {
- get;
- set;
- }
- }
- }
- using System.Collections.Generic;
- namespace TreeView.Models {
- public class AuthorViewModel
- {
- public AuthorViewModel()
- {
- BookViewModel = new List < BookViewModel > ();
- }
- public int Id
- {
- get;
- set;
- }
- public string Name
- {
- get;
- set;
- }
- public bool IsAuthor
- {
- get;
- set;
- }
- public IList < BookViewModel > BookViewModel
- {
- get;
- set;
- }
- }
- }
- using System.Collections.Generic;
- using System.Linq;
- using System.Web.Mvc;
- using TreeView.Models;
- namespace TreeView.Controllers
- {
- public class HomeController : Controller
- {
- [HttpGet]
- public ActionResult Index()
- {
- List<AuthorViewModel> model = new List<AuthorViewModel>();
- AuthorViewModel firstAuthor = new AuthorViewModel
- {
- Id = 1,
- Name = "John",
- BookViewModel = new List<BookViewModel>{
- new BookViewModel{
- Id=1,
- Title = "JQuery",
- IsWritten = false
- }, new BookViewModel{
- Id=1,
- Title = "JavaScript",
- IsWritten = false
- }
- }
- };
- AuthorViewModel secondAuthor = new AuthorViewModel
- {
- Id = 2,
- Name = "Deo",
- BookViewModel = new List<BookViewModel>{
- new BookViewModel{
- Id=3,
- Title = "C#",
- IsWritten = false
- }, new BookViewModel{
- Id=4,
- Title = "Entity Framework",
- IsWritten = false
- }
- }
- };
- model.Add(firstAuthor);
- model.Add(secondAuthor);
- return View("Index", model);
- }
- [HttpPost]
- public ActionResult Index(List<AuthorViewModel> model)
- {
- List<AuthorViewModel> selectedAuthors = model.Where(a => a.IsAuthor).ToList();
- List<BookViewModel> selectedBooks = model.Where(a => a.IsAuthor)
- .SelectMany(a => a.BookViewModel.Where(b => b.IsWritten)).ToList();
- return View();
- }
- }
- }
Bootstrap CSS is already added to the application but we write a new custom CSS for the tree view design. The following is the code snippet for the tree CSS.
- .tree li {
- margin: 0px 0;
- list-style-type: none;
- position: relative;
- padding: 20px 5px 0px 5px;
- }
- .tree li::before{
- content: '';
- position: absolute;
- top: 0;
- width: 1px;
- height: 100%;
- right: auto;
- left: -20px;
- border-left: 1px solid #ccc;
- bottom: 50px;
- }
- .tree li::after{
- content: '';
- position: absolute;
- top: 30px;
- width: 25px;
- height: 20px;
- right: auto;
- left: -20px;
- border-top: 1px solid #ccc;
- }
- .tree li a{
- display: inline-block;
- border: 1px solid #ccc;
- padding: 5px 10px;
- text-decoration: none;
- color: #666;
- font-family: 'Open Sans',sans-serif;
- font-size: 14px;
- font-weight :600;
- border-radius: 5px;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- }
- /*Remove connectors before root*/
- .tree > ul > li::before, .tree > ul > li::after{
- border: 0;
- }
- /*Remove connectors after last child*/
- .tree li:last-child::before{
- height: 30px;
- }
- /*Time for some hover effects*/
- /*We will apply the hover effect the the lineage of the element also*/
- .tree li a:hover, .tree li a:hover+ul li a {
- background: #dd4814; color: #ffffff; border: 1px solid #dd4814;
- }
- /*Connector styles on hover*/
- .tree li a:hover+ul li::after,
- .tree li a:hover+ul li::before,
- .tree li a:hover+ul::before,
- .tree li a:hover+ul ul::before{
- border-color: #dd4814;
- }
- .tree-checkbox{
- margin :4px !important;
- }
- .tree:before {
- border-left: 1px solid #ccc;
- bottom: 16px;
- content: "";
- display: block;
- left: 0;
- position: absolute;
- top: -21px;
- width: 1px;
- z-index: 1;
- }
- .tree ul:after {
- border-top: 1px solid #ccc;
- content: "";
- height: 20px;
- left: -29px;
- position: absolute;
- right: auto;
- top: 37px;
- width: 34px;
- }
- *:before, *:after {
- box-sizing: border-box;
- }
- *:before, *:after {
- box-sizing: border-box;
- }
- .tree {
- overflow: auto;
- padding-left: 0px;
- position: relative;
- }
- @model List
- <TreeView.Models.AuthorViewModel>
- @section head{
- @Styles.Render("~/Content/css/tree.css")
- }
- <div class="panel panel-primary">
- <div class="panel-heading panel-head">Author Book Tree View</div>
- <div id="frm-author" class="panel-body">
- @using (Html.BeginForm())
- {
- <div class="tree">
- @for (int i = 0; i < Model.Count(); i++)
- {
- <ul>
- <li>
- <a href="#">
- @Html.CheckBoxFor(model => model[i].IsAuthor, new { @class = "tree-checkbox parent", @id = @Model[i].Id })
- <label for=@i>
- <strong>Author:</strong>
- @Html.DisplayFor(model => model[i].Name)
- </label>
- </a>
- <ul>
- @for (int j = 0; j < Model[i].BookViewModel.Count(); j++)
- {
- int k = 1 + j;
- @Html.HiddenFor(model => model[i].BookViewModel[j].Id)
- <li>
- <a href="#">
- @Html.CheckBoxFor(model => model[i].BookViewModel[j].IsWritten, new { @class = "tree-checkbox node-item", @iid = i + "" + j })
- <label for=@i@j>
- <strong>Book @(k):</strong> @Html.DisplayFor(model => model[i].BookViewModel[j].Title)
- </label>
- </a>
- </li>
- }
- </ul>
- </li>
- </ul>
- }
- </div>
- <div class="form-group">
- <div class="col-lg-9"></div>
- <div class="col-lg-3">
- <button class="btn btn-success" id="btnSubmit" type="submit">
- Submit
- </button>
- </div>
- </div>
- }
- </div>
- </div>
- @section scripts{
- @Scripts.Render("~/Scripts/tree.js")
- }
- (function($)
- {
- function Tree() {
- var $this = this;
- function treeNodeClick()
- {
- $(document).on('click', '.tree li a input[type="checkbox"]', function() {
- $(this).closest('li').find('ul input[type="checkbox"]').prop('checked', $(this).is(':checked'));
- }).on('click', '.node-item', function() {
- var parentNode = $(this).parents('.tree ul');
- if ($(this).is(':checked')) {
- parentNode.find('li a .parent').prop('checked', true);
- } else {
- var elements = parentNode.find('ul input[type="checkbox"]:checked');
- if (elements.length == 0) {
- parentNode.find('li a .parent').prop('checked', false);
- }
- }
- });
- };
- $this.init = function() {
- treeNodeClick();
- }
- }
- $(function() {
- var self = new Tree();
- self.init();
- })
- }(jQuery))
- When we select an author parent node then all the associated books will be selected.
- When a book is selected the associated parent author will be selected automatically.
- When all child book nodes are selected for a parent author node then the parent node will be selected.
- When the parent node is unselected then the child books will be automatically unselected.
Figure 1 shows the parent child (author-book) tree view.

G Krishna RaoPosted May 29, 2019, 4:41 AM
Nice article..How to make expandable tree view..?I mean sub-sub module..Plz guide..?
Alfredo BochePosted Sep 24, 2018, 2:15 PM
Gracias, una duda, ?como puedo mostrar una tabla con mas de dos columnas con estas propiedades?
Mg KyaingPosted Feb 7, 2017, 6:36 AM
Thanks :-) Sir ! Thanks a lot for your Code.
Sandeep Singh ShekhawatPosted Dec 25, 2016, 11:30 AM
Thanks Mahesh Chand Sir ! Thanks all for your words..
Mahesh ChandPosted Dec 24, 2016, 12:02 PM
Wow! I like the design and look of this TreeView.
Shahbaz AhmadPosted Apr 18, 2016, 8:34 AM
how can i make expandable treeview???
ali kipelPosted Mar 3, 2016, 3:15 AM
How can get changed model?? in cshtml
Rajeesh MenothPosted Jul 25, 2015, 6:55 AM
Good One..Waiting for more articles in ur side
Sandeep Singh ShekhawatPosted Jul 24, 2015, 2:45 PM
Thanks all :)
Santhakumar MunuswamyPosted Jul 24, 2015, 2:18 PM
Good one
Neeraj KumarPosted Jul 24, 2015, 12:51 PM
Nice Article
Pankaj Kumar ChoudharyPosted Jul 24, 2015, 12:23 PM
Nice Explain Sir............
Shridhar SharmaPosted Jul 24, 2015, 12:20 PM
good one sir.
Sandeep Singh ShekhawatPosted Jul 24, 2015, 10:31 AM
Thanks all :)
Nilesh JadavPosted Jul 24, 2015, 9:02 AM
Nice one sir
Gopi ChandPosted Jul 24, 2015, 8:41 AM
Well done
RakeshPosted Jul 24, 2015, 8:09 AM
Nice one
Rakesh KalluriPosted Jul 24, 2015, 7:50 AM
Good One sir.
Rahul Kumar SaxenaPosted Jul 24, 2015, 7:40 AM
Good Show...