Introduction
Dynamic treeview
with drag and drop is useful whenever you need to arrange employer or documents according to particular nested hierarchy. Assume one personnel in the organization should report his or her tasks to upper manager and this manager has another upper manager and so on. In the other example, you want to arrange documents and define their parents such as { Finance -->Salary -->Personal} or { office -->letter -->import }. Kendoui treeview has the ability for drag and drop but in their example, they used static string
in json format such as [{ id: "1", text: "P1", items: [{ id: "5", text: "P2"}] }]
that you should pass this string
to kendo treeview
data source. I write a method to generate these json to pass data source and after you change node location (parent), it will be saved.
Background
Firstly, you need to add some CSS and JS file from kendoui treeview
to your project.
For more information about kendo UI treeview
, look at the below link to know about binding local data and its structure:
Using this Code
Given below is a brief description of how I create a method to generate json format.
Step 1: Database
Firstly, create a database and then table as personal:
Step 1.1: Table
Then fill this table:
Step 2: Data Model
Then make Entity Data Model (fast and easy):
Step 3: Model Class Inside Model Folder
This code is written in MVC so the below section is located in Model folder from table.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Treeview.Models
{
public class Personal
{
public int ID { get; set; }
public int Parent_ID { get; set; }
public string Name { get; set; }
}
}
Step 4: Main Method Inside Controller Folder
I have created "PersonalController.cs" inside controllers folder as follows:
Actually, the below logic description will generate self reference table as JSON format and then it passes its content to treeview
data source.
I have generated this method for the above data model in step 3 which illustrates there are personnel in organization who may be have a manager or employer, if your database is different, then you should look at code and change that a little.
To generate hierarchical Data Source as JSON file, follow these steps and for full explanation, follow the link.
Step 1
Make a **nested** method so called Treeview
:
public string Treeview(int itemID, string mystr, int j, int flag)
whose output is json as string
and get:
itemID
--> ID for current node mystr
--> previous json string
- {in every self call this method, new
string
will be added to mystr
} j
is inner counter flag
is illustrated if current node has child or not
Step 2
First one you call this method from your action in MVC or other part of your application call like that Treeview(0,””,0,0)
.
- Assume you do not know the current node, so
itemid
is equal to zero - The first time, you do not have any
string
for json j = 0
as the same token flag = 0
as the same token
Step 3
Check whether this current node has parent or not ?
- Main node root: if you are, just enter this method, so assume you have to:
- Select from data base
- Nodes which have no parents and their parent id is equal to
NULL
- Here, generate your json
string
like **mystr = "["**
- Nested node: If this method has been called more than once, check all nodes:
- where their parent is equal to
itemid
- here, generate your json
string
like **mystr = ",item:["**
Step 4
Now you have a list of data which you have tried from the third step:
- Make a
foreach
loop and call each node and write it like foreach
(item in querylist
)
**mystr = { id: "" , text: ""**
- Inside this loop, check whether this node has child or not?
Querylist= select personal where reportsto=item.id
- **(It has child)** --> call again
Treeview
method such as:
mystr = Treeview (item.id, mystr, i,1)
Now your item.id
is crrent node, mystr
is the whole string
which is generated
until now i
as j
and flag
is equal to one as this node is parent and has child
- **(It has No Child && this node is not last node)**
**mystr =" }, "**
- **(It has No Child && this node is last node)**
- Count number of parents of this node
Foreach parent put **mystr = "}]"**
- Count number of child of parents of this node
if (Child = 0) **mystr = "}]"**
if (Child > 0) **mystr = "}]"**
- if (This node is the last child node && parent of this node is last parent)
**mystr = "},"**
- if (This node is the last child node && parent of this node is last parent &&
flag=1 )
**mystr =" },"**
- if (This node is the last child node && parent of this node is last parent && flag=0 )
**mystr =" }]"**
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using System.Diagnostics;
using System.Text;
namespace Treeview.Controllers
{
public class PersonalController : Controller
{
int mainNode = 0;
int childquantity = 0;
int myflag;
[HttpPost]
public ActionResult SaveNode(string childid, string parentid)
{
if (childid != null && parentid != null && parentid != childid )
{
string source = childid;
string destination = parentid;
using (var ctx = new TreeviewEntities())
{
var personals = ctx.Personals.Where(m => m.Name == source).First();
var personalsParent = ctx.Personals.Where(m => m.Name == destination).First();
if (personalsParent.ReportsTo!=personals.ID)
{
personals.ReportsTo = Convert.ToInt16(personalsParent.ID);
ctx.SaveChanges();
}
}
}
return RedirectToAction("Index");
}
public string Treeview(int itemID, string mystr, int j, int flag)
{
List<Personal> querylist = new List<Personal>();
var ctx = new TreeviewEntities();
if (flag==0)
{
querylist = (from m in ctx.Personals
where m.ReportsTo == null
select m).ToList();
mainNode = querylist.Count;
mystr += "[";
}
if (flag == 1)
{
querylist = (from m in ctx.Personals
where m.ReportsTo == itemID
select m).ToList();
mainNode = querylist.Count;
mystr += ",items:[";
}
int i=1;
foreach (var item in querylist)
{
myflag = 0;
mystr += "{id:\"" + item.ID +
"\",text:\"" + item.Name + "\"";
List<Personal> querylistParent = new List<Personal>();
querylistParent = (from m in ctx.Personals
where m.ReportsTo == item.ID
select m).ToList();
childquantity = querylistParent.Count;
if (childquantity > 0)
{
mystr = Treeview(item.ID, mystr, i, 1);
}
else if (childquantity == 0 && i < querylist.Count)
{
mystr += "},";
}
else if (childquantity == 0 && i == querylist.Count)
{
int fcheck2=0;
int fcheck3 = 0;
int counter = 0;
int flagbreak = 0;
int currentparent;
List<Personal> parentquery ;
List<Personal> childlistquery;
TempData["counter"] =0;
currentparent = Convert.ToInt16(item.ReportsTo);
int coun;
while (currentparent != 0)
{
fcheck2 = 0;
fcheck3 = 0;
parentquery = new List<Personal>();
parentquery = (from m in ctx.Personals
where m.ID == currentparent
select m).ToList();
var rep2 = (from h in parentquery
select new { h.ReportsTo }).First();
childlistquery = new List<Personal>();
childlistquery = (from m in ctx.Personals
where m.ReportsTo == currentparent
select m).ToList();
foreach (var item22 in childlistquery)
{
if (mystr.Contains(item22.ID.ToString()))
{
if (item22.ReportsTo == currentparent)
{
fcheck3 += 1;
if (fcheck3 == 1)
{
counter += 1;
}
}
}
else
{
myflag = 1;
if (item22.ReportsTo == currentparent)
{
fcheck2+=1;
if (fcheck2==1)
{
counter -= 1;
flagbreak = 1;
}
}
}
}
var result55 =
(from h in parentquery select new { h.ID }).First();
coun = Convert.ToInt16(result55.ID);
TempData["coun"] = Convert.ToInt16(coun);
currentparent = Convert.ToInt16(rep2.ReportsTo);
if (flagbreak == 1)
{
break;
}
}
for (int i2 = 0; i2 < counter; i2++)
{
mystr += "}]";
}
List<Personal> lastchild = new List<Personal>();
lastchild = (from m in ctx.Personals
where m.ReportsTo == item.ReportsTo
select m).ToList();
List<Personal> lastparent = new List<Personal>();
lastparent = (from m in ctx.Personals
where m.ReportsTo == null
select m).ToList();
if (lastchild.Count > 0)
{
var result_lastchild =
(from h in lastchild select new { h.ID }).Last();
var result_lastparent =
(from h in lastparent select new { h.ID }).Last();
int mycount = Convert.ToInt16(TempData["coun"]);
if (item.ID == result_lastchild.ID &&
mycount == result_lastparent.ID && myflag == 0)
{
mystr += "}]";
}
else if (item.ID == result_lastchild.ID &&
mycount == result_lastparent.ID && myflag == 1)
{
mystr += "},";
}
else if (item.ID == result_lastchild.ID &&
mycount != result_lastparent.ID)
{
mystr += "},";
}
}
else if (lastchild.Count == 0 && item.ReportsTo == null)
{
mystr += "}]";
}
}
i++;
}
return mystr;
}
public ActionResult Index()
{
ViewData["treeviewds"] = Treeview(0, "", 0, 0);
return View();
}
}
}
Step 5: UI Inside View
Then I have created "Index.cshtml" inside Views -->Personal folder as follows.
Step 5.1: Head
In the head
section, you should define CSS and JS files:
Step 5.2: Body
Then make treeview div
for appending json string to it and tvformat
to pass viewdata["treeviewds"]
:
Step 5.3: Script
Then write script for getting treeview
data from database and post (save) node which has been changed their parents (location):
Step 5.4: CSS
Then make style
for it.
History
30th July, 2014
I have added demo link to this article.
1st August, 2014
I have corrected two bugs in this article, first one if you click one node and then drop it to itself in SaveNode
action, I have edited it if parentid == childid
so do not do anything.
The second one is you cannot make circle in treeview
such as P1
is parent for P2
and also P2
is parent for P1
is incorrect and makes a circle.
Feedback
Feel free to leave any feedback on this article; it is a pleasure to see your comments and vote about this code. If you have any questions, please do not hesitate to ask me here.