Drag And Drop In jsTree

Introduction

 
This article demonstrates how to drag and drop nodes using jsTree.
 
What is jsTree?
 
If you haven’t read the introductory post on jsTree, I would recommend reading the article jsTree.
 
What we do here 
 
Here we are going to use CheckBox and dnd plugin to implement the drag and drop.
 
And we are going to implement drag and drop from one tree to another tree and restrict drop functionality from dragged tree.
 
Load Tree One and Tree Two
  1. <style>  
  2.     .border {  
  3.         border: 1px solid #dee2e6 !important;  
  4.     }  
  5.   
  6.     .jstree-icon {  
  7.         color: cornflowerblue !important;  
  8.     }  
  9. </style>  
  10.   
  11. <h2>Drag And Drop In jsTree</h2>  
  12.   
  13. <div class="container-fluid" id="dsContainer">  
  14.     <div class="row">  
  15.         <div class="col-md-6 border">  
  16.             <div class="">  
  17.                 <div>Tree One</div>  
  18.                 <div class="" id="treeOne"></div>  
  19.             </div>  
  20.         </div>  
  21.         <div class="col-md-6 border">  
  22.             <div class="">  
  23.                 <div>Tree Two</div>  
  24.                 <div class="" style="min-height: 264px;" id="treeTwo"></div>  
  25.             </div>  
  26.         </div>  
  27.           
  28.     </div>  
  29. </div>  
  30.   
  31. <script>  
  32.     $(document).ready(function () {  
  33.         fnLoadTreeOne();  
  34.         fnLoadTreeTwo();  
  35.     })  
  36.   
  37.     function fnLoadTreeOne() {  
  38.         var dataSource = [  
  39.             { id: 'fields', parent: '#', text: 'Tree One Fields', type: 'folder' },  
  40.             { id: '1', parent: 'fields', text: 'Field1', type: 'file' },  
  41.             { id: '2', parent: 'fields', text: 'Field2', type: 'file' },  
  42.             { id: '3', parent: 'fields', text: 'Field3', type: 'file' },  
  43.             { id: '4', parent: 'fields', text: 'Field4', type: 'file' },  
  44.             { id: '5', parent: 'fields', text: 'Field5', type: 'file' },  
  45.             { id: '6', parent: 'fields', text: 'Field6', type: 'file' },  
  46.             { id: '7', parent: 'fields', text: 'Field7', type: 'file' },  
  47.             { id: '8', parent: 'fields', text: 'Field8', type: 'file' },  
  48.             { id: '9', parent: 'fields', text: 'Field9', type: 'file' },  
  49.             { id: '10', parent: 'fields', text: 'Field10', type: 'file' },  
  50.         ];  
  51.         //jsTree instance  
  52.         $('#treeOne').jstree({  
  53.             "core": {  
  54.                 "data": dataSource  
  55.             },  
  56.             "types": {  
  57.                 "folder": {  
  58.                     "icon""fa fa-folder"  
  59.                 },  
  60.                 "file": {  
  61.                     "icon""fa fa-file"  
  62.                 }  
  63.             },  
  64.             "plugins": ["types","checkbox"]  
  65.         }).bind('ready.jstree'function (e, data) {  
  66.             $('#treeOne').jstree('open_all')  
  67.         })  
  68.     }  
  69.     function fnLoadTreeTwo() {  
  70.         var dataSource = [  
  71.             { id: 'fields', parent: '#', text: 'Tree Two Fields', type: 'folder' },  
  72.         ];  
  73.         $('#treeTwo').jstree({  
  74.             "core": {  
  75.                 "data": dataSource[0]  
  76.             },  
  77.             "types": {  
  78.                 "folder": {  
  79.                     "icon""fa fa-folder"  
  80.                 },  
  81.                 "file": {  
  82.                     "icon""fa fa-file"  
  83.                 }  
  84.             },  
  85.             "plugins": ["types"]  
  86.         }).bind('ready.jstree'function (e, data) {  
  87.             $('#treeTwo').jstree('open_all')  
  88.         })  
  89.     }  
  90. </script>  
 
From the above code and image, you can see that we have created two jstrees. TreeOne & TreeTwo and enabled checkbox plugin for TreeOne. This is the basic load before we get into drag & drop.
 
Step 1
 
Enable dnd plugin in both trees.
 
TreeOne--> "plugins": ["types","checkbox", "dnd"]
TreeTwo--> "plugins": ["types", "dnd"]
 
Step 2
 
If you go through the jsTree article which i mentioned above, you can find that we have to use "check_callback" : true in trees to handle the plugin functionalities. 
 
Add "check_callback" : true in core configuration in both trees.
 
Now if you check the application until  step 2, default drag and drop flow will be working. The drop target will be the treeTwo parent node (when you hover the parent node with the dragged node, then it will be added to tree). Now drop will happen for both trees. But we have to restrict for TreeOne (that is one of our requirement). And also the changes won't reflect in the datasource unless we add the new dropped node to the treeTwo datasource.
 
You can check the datasource (list of nodes and its information in the form of json) in console using below code.
 
$('#treeTwo').jstree(true).settings.core.data 
 
Step 3
 
Restrict drop functionality for Tree One.
 
To restrict drop for TreeOne, replace check_callback function like below.
  1. 'check_callback'function (operation, node, node_parent, node_position, more) {  
  2.      if (operation === "move_node") {  
  3.            return false  
  4.        }  
  5. }  
  6.    
So the treeOne drop will not happen after we adding above lines. 
 
Events in dnd plugin
 
Before going to Step 4, have a look about Events in dnd plugin. 
  1. dnd_start.vakata
  2. dnd_move.vakata
  3. dnd_stop.vakata
  1. $(document).on('dnd_move.vakata'function (e, data) {  
  2.      //your code  
  3. })  
If we need to do something when a start/stop/ moves the nodes while dragging and dropping, then this is the place.
 
Step 4
 
So far we have loaded the jstree, implemented drag drop, restricted drop for a tree. Now we are going save the dropped nodes to the treeTwo jsTree. 
  1. $(document).on('dnd_stop.vakata', function (e, data) {  
  2.             var selectedNodes = $('#treeOne').jstree('get_selected'true);  
  3.             if (selectedNodes.length > 0) {  
  4.                 var target = data.event.target;  
  5.                 var closestJsTree = target.closest('.jstree');  
  6.                 if (closestJsTree) {  
  7.                     var treeId = closestJsTree.id;  
  8.                     if (treeId == "treeTwo") {  
  9.                         //fnDropNodes(treeId, selectedNodes); //loop through the selected nodes and add to the datasource and refresh the jstree  
  10.                     } else {  
  11.                         return false;  
  12.                     }  
  13.                 } else {  
  14.                     return false;  
  15.                 }  
  16.             }  
  17.         })  
We have used dnd_stop event (will be triggered when nodes are dropped). As you can see in the code, selectedNodes variable will have the selected node's information. Loop through the nodes and create a new datasource with the existing treeTwo jstree and refresh the tree.
  1. $('#treeTwo').jstree(true).settings.core.data = newDataSource  
  2. $('#treeTwo').jstree(true).refresh();  
 

Summary

 
In this article, we have seen how to implement drag and drop multiple nodes using jstree.