Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dynamic Treeview with Drag and Drop by Kendo

0.00/5 (No votes)
4 Apr 2019 4  
This article explains how to make data source for kendoTreeView, particularly it is designed for organization chart such as personals or documents which need nested query, after drag and drop one node to another one, it will save it. Look at the demo.

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:

  1. itemID --> ID for current node
  2. mystr --> previous json string
  3. {in every self call this method, new string will be added to mystr}
  4. j is inner counter
  5. 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).

  1. Assume you do not know the current node, so itemid is equal to zero
  2. The first time, you do not have any string for json
  3. j = 0 as the same token
  4. flag = 0 as the same token

Step 3

Check whether this current node has parent or not ?

  1. 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 = "["**
  2. 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:

  1. Make a foreach loop and call each node and write it like
  2. foreach (item in querylist)
    **mystr = { id: "" , text: ""**
    
  3. Inside this loop, check whether this node has child or not?
    Querylist= select personal where reportsto=item.id
    1. **(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

    2. **(It has No Child && this node is not last node)**
      **mystr =" }, "**
    3. **(It has No Child && this node is last node)**
      1. Count number of parents of this node
        Foreach parent put **mystr = "}]"**
      2. Count number of child of parents of this node
        1. if (Child = 0) **mystr = "}]"**
        2. if (Child > 0) **mystr = "}]"**
          1. if (This node is the last child node && parent of this node is last parent)
            **mystr = "},"**
          2. if (This node is the last child node && parent of this node is last parent &&
            flag=1 )
            **mystr =" },"**
          3. 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)
        {
            //*****REVISION******Do not allow reportsto = itself 
            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();

                    //***check
                    //*****REVISION******Do not allow make circle in data base 
                    //such as P1 is parent for P2 and also P2 is parent for 
                    //P1 ==> Prevent these mistake by checking it
                    //
           
                    if (personalsParent.ReportsTo!=personals.ID)
                    {
                        personals.ReportsTo = Convert.ToInt16(personalsParent.ID);

                        ctx.SaveChanges();
                    }
                    //***check                    
                }                
            }
            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:[";
            }
            
            //Below line shows an example of how to make parent node with his child
            //[{ id: "1", text: "P1", items: [{ id: "5", text: "P2" }] }]

           int i=1;
                foreach (var item in querylist)
                {
                            myflag = 0;
                            mystr += "{id:\"" + item.ID + 
                            "\",text:\"" + item.Name + "\"";
                            List<Personal> querylistParent = new List<Personal>();
                            //Check this parent has child or not , if yes how many?
                            querylistParent = (from m in ctx.Personals
                                           where m.ReportsTo == item.ID
                                           select m).ToList();
                            childquantity = querylistParent.Count;
                            //If Parent Has Child again call Treeview with new parameter
                            if (childquantity > 0)
                            {
                                mystr = Treeview(item.ID, mystr, i, 1);
                            }
                            //No Child and No Last Node
                            else if (childquantity == 0 && i < querylist.Count)
                            {
                                mystr += "},";
                            }
                            //No Child and Last Node
                            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)
                                {
                                    //count parent of parent
                                   
                                     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();
                                   
                                    //put {[ up to end
                                    
                                    //list of child
                                     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 += "},";
                                    }                                    
                                }
                                //  finish }]
                                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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here