Implement Custom ContextMenu In jsTree

Introduction

 
jsTree Context Menu plugin will make you right-click the node and show a list of configurable actions in a menu. This article demonstrates how to create a custom menu using jsTree.
 

What is jsTree?

 
If you haven’t read the introductory post on jsTree, I would recommend reading the article jsTree
 
Include Font Awesome for Icons
 
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> 
 
ContextMenu in jsTree 
 
Add ContextMenu feature in jsTree is a small change. If you read the above jsTree article you can see there will multiple plugins to enable different features.
 
Below is the line to add the Context Menu feature
 
"plugins": ["contextmenu"]
 
 Once we add a plugin, you will get the below default menu:
 
Implement Custom ContextMenu In jsTree
Please note that we have to add “check_callback” as true to work menu functionality.
 
But here, we are going to override the default menu and we will customize the menu for our requirement.
 
Here, I have taken the example of setting a field to ascending or descending using the jstree contextmenu plugin. 
  1. <div id="divJsTreeExample"></div>  
  2.   
  3. <script>  
  4.     $(document).ready(function () {  
  5.         fnLoadJsTreeInstance()  
  6.   
  7.     })  
  8.     function fnLoadJsTreeInstance() {  
  9.         var treeDataSource = [  
  10.             { id: 'fields', parent: '#', text: 'Fields', type: 'folder' },  
  11.             { id: '1', parent: 'fields', text: 'Field1', type: 'file', field: 'Field1''dir''' },  
  12.             { id: '2', parent: 'fields', text: 'Field2', type: 'file', field: 'Field2','dir''' },  
  13.             { id: '3', parent: 'fields', text: 'Field3', type: 'file', field: 'Field3''dir'''  },  
  14.         ]  
  15.         //jsTree instance  
  16.         $('#divJsTreeExample').jstree({  
  17.             "core": {  
  18.                 "data": treeDataSource  
  19.             },  
  20.             "types": {  
  21.                 "folder": {  
  22.                     "icon""fa fa-folder"  
  23.                 },  
  24.                 "file": {  
  25.                     "icon""fa fa-file"  
  26.                 }  
  27.             },  
  28.             "contextmenu": {  
  29.                 items: function ($node) {  
  30.                     return {  
  31.                         "asc": {  
  32.                             "label""<span class='asc'>Ascending <i class='fa fa-check dir-selected'></i></span>",  
  33.                             "icon""fa fa-sort-amount-asc",  
  34.                             "action"function (obj) {  
  35.                                 fnChangeSortFieldsDirection('asc')  
  36.                             },  
  37.                             "_class""asc"  
  38.                         },  
  39.                         "desc": {  
  40.                             "label""<span class='desc'>Descending <i class='fa fa-check dir-selected'></i></span>",  
  41.                             "icon""fa fa-sort-amount-desc",  
  42.                             "action"function (obj) {  
  43.                                 fnChangeSortFieldsDirection('desc')  
  44.                             },  
  45.                             "_class""desc"  
  46.                         }  
  47.                     }  
  48.                 },  
  49.             },  
  50.             "plugins": ["types""contextmenu"]  
  51.         }).bind('ready.jstree'function (e, data) {  
  52.             $('#divJsTreeExample').jstree('open_all')  
  53.         }).bind("show_contextmenu.jstree"function (e, data) {  
  54.             if (data.node.parent == "#") {  
  55.                 $.vakata.context.hide()  
  56.             } else {  
  57.                 var currentDirection = data.node.original.dir  
  58.                 if (currentDirection) {  
  59.                     var hideCheck = currentDirection == "asc" ? "desc" : "asc"  
  60.                     $('.jstree-contextmenu li.' + hideCheck + ' i.dir-selected').hide()  
  61.                 } else {  
  62.                     $('.jstree-contextmenu li i.dir-selected').hide()  
  63.                 }  
  64.             }  
  65.         })  
  66.     }  
  67.   
  68.     function fnChangeSortFieldsDirection(selectedDirection) {  
  69.         var nodeObj = $('#divJsTreeExample').jstree('get_selected'true)  
  70.         var treeSource = $('#divJsTreeExample').jstree(true).settings.core.data  
  71.         if (!nodeObj[0].original.dir  || (nodeObj[0].original.dir != selectedDirection)) {  
  72.             $.each(treeSource, function (i, treeNode) {  
  73.                 if (treeNode.id == nodeObj[0].id) {  
  74.                     treeNode.dir = selectedDirection  
  75.                     treeNode.text = treeNode.field + "(" + selectedDirection + ")"  
  76.                 }  
  77.             })  
  78.             $('#divJsTreeExample').jstree(true).settings.core.data = treeSource  
  79.             $('#divJsTreeExample').jstree(true).refresh()  
  80.         }  
  81.     }  
  82.      
  83. </script>   
Code Explanation
 
In the above code, I have used the JSON datasource to load the tree. You can see that contextmenu will be added in the plugins array under jstree instance configuration. To add Custom Menu, we have to add the menu under items as you can see in the code.
 
We have used asc and desc for the menu items.
 
Properties used in the Menu Item:
  1. label --> The given string or HTML will be displayed when we right-click the node
  2. icon --> Icon to display before the text.
  3. action --> Event will be triggered when the menu item is clicked.
  4. _class --> any custom class can be added here.
Event for context menu shown:
  1. .bind("show_contextmenu.jstree"function (e, data) {  
  2.       
  3. })  
Because we have both the parent and child here, we have to prevent the context menu to open when we right-click the parent node.
 
So the line $.vakata.context.hide() will do the prevent functionality.
 
If the selected node is child, then we will update the direction and refresh the tree. 
 
Event fnChangeSortFieldsDirection will get the currently selected node and update the direction and refresh the tree.
 
Output 
 
Implement Custom ContextMenu In jsTree
 
Implement Custom ContextMenu In jsTree
Implement Custom ContextMenu In jsTree
 

Summary 

 
In this article, we have seen how to create a custom context menu using jstree.