thejustv
thejustv

Reputation: 2035

How to disable nth level node if any (n-1)th node is selected in jsTree

Hi am using jsTree and created the below shown Tree

enter image description here

Now i want to disable n th node if (n-1) th node is selected,ie user cant able to select different level of nodes.

eg:

  1. if user selected Koramangala,then infosys,Accenture,TCS,IBM,Wipro and their child nodes should be disable
  2. If Bangalore is selected,Koramangala,electronicCity,WhiteField,Marathahally and their child should be disabled and disable same level childs in US& UK

Is it possible to achieve this requirement ????

Thanks in advance

Upvotes: 3

Views: 2454

Answers (3)

SharpCoder
SharpCoder

Reputation: 19163

All the other answers\fiddles listed above works in most scenarios but one. All the above scenarios works fine as long as all the nodes are expanded (becuase once you collapse a node, it is removed from the dom).

Assume you select a node at level three and then you collapse the node at level three and then you select a node at level 1, it system does not un-select level 3 node (as it was removed from dom when node was collapsed) and nodes at level 1 and 3 remains selected.

To fix the issue, I am sending the node an additional field in the JSON call level which tells you about the current level of the node.

var myTree = $('#tree');

myTree .on('changed.jstree', function(event, data) {
      mee.disableTreeNodesAtOtherLevels(event,data,myTree );
    });

disableTreeNodesAtOtherLevels(event,data, tree){
    var currentlevel = parseInt($('#' + data.node.id).attr('aria-level'));
    var selectedNodes = tree.jstree(true).get_selected(true);
    for (var i = 0; i < selectedNodes.length; i++) {
      if(selectedNodes[i].original.level !== currentlevel){
         tree.jstree(true).deselect_node(selectedNodes[i], true);
      }
    }
  }

All this works based on assumption the data you are binding to tree is having a property called level

Upvotes: 0

thejustv
thejustv

Reputation: 2035

Solution for the above mentioned requiremnt will be available here in jsFfiddle

Here am listing the features

  • At a time,only same level of nodes can be selectable
  • If select nth level node,then all lower level nodes will be disabled
  • If select nth level node and after that if select any higher level node is selected,then all lower level nodes selection will be removed

Here am adding the jquery code

var data = [{"id":"1","text":"India","state":{"opened":false},"parent":"#", "state": { "opened":true } },{"id":"1-1","text":"Banglore", "state": { "opened":true }, "parent":"1"},{"id":"1-1-1","text":"Koramangala","state":{"opened":false},"parent":"1-1"},{"id":"1-1-1-1","text":"Infosys   ","state":{"opened":false},"parent":"1-1-1"},{"id":"1-1-1-1-1","text":"D","state":{"opened":false},"parent":"1-1-1-1"},{"id":"1-1-1-1-2","text":"E","state":{"opened":false},"parent":"1-1-1-1"},{"id":"1-1-1-1-3","text":"G","state":{"opened":false},"parent":"1-1-1-1"},{"id":"1-1-1-3","text":"Accenture ","state":{"opened":false},"parent":"1-1-1"},{"id":"1-1-1-3-8","text":"C","state":{"opened":false},"parent":"1-1-1-3"},{"id":"1-1-1-3:9","text":"E","state":{"opened":false},"parent":"1-1-1-3"},{"id":"1-1-2","text":"Electronic City","state":{"opened":false},"parent":"1-1"},{"id":"1-1-2-2","text":"TCS       ","state":{"opened":false},"parent":"1-1-2"},{"id":"1-1-2-2-4","text":"C","state":{"opened":false},"parent":"1-1-2-2"},{"id":"1-1-2-2-5","text":"E","state":{"opened":false},"parent":"1-1-2-2"},{"id":"1-1-2-2-6","text":"F","state":{"opened":false},"parent":"1-1-2-2"},{"id":"1-1-2-2-7","text":"G","state":{"opened":false},"parent":"1-1-2-2"},{"id":"1-1-3","text":"WhiteField","state":{"opened":false},"parent":"1-1"},{"id":"1-1-3-4","text":"IBM       ","state":{"opened":false},"parent":"1-1-3"},{"id":"1-1-3-4-10","text":"F","state":{"opened":false},"parent":"1-1-3-4"},{"id":"1-1-4","text":"Marathahally","state":{"opened":false},"parent":"1-1"},{"id":"1-1-4-5","text":"Wipro     ","state":{"opened":false},"parent":"1-1-4"},{"id":"1-1-4-5-11","text":"G","state":{"opened":false},"parent":"1-1-4-5"},{"id":"1-2","text":"Chennai","state":{"opened":false},"parent":"1"},{"id":"1-2-5","text":"sholinganallur","state":{"opened":false},"parent":"1-2"},{"id":"1-2-6","text":"Tiruvanmiyur","state":{"opened":false},"parent":"1-2"},{"id":"2","text":"UK","state":{"opened":false},"parent":"#"},{"id":"2-3","text":"London","state":{"opened":false},"parent":"2"},{"id":"3","text":"US","state":{"opened":false},"parent":"#"},{"id":"3-4","text":"Texas","state":{"opened":false},"parent":"3"},{"id":"3-5","text":"Washington","state":{"opened":false},"parent":"3"},{"id":"3-6","text":"California","state":{"opened":false},"parent":"3"}]

$.jstree.defaults.core = {};
var currentlevel;
$('#tree')
    .on('changed.jstree', function (event, data) {
        if( data.action == 'select_node'){ 
            $('#tree').find('li').removeClass('disabled_node');
console.log('select '+ data.node.text);           

            currentlevel = parseInt( $('#'+data.node.id).attr('aria-level') );
            $('#tree').find('li').each( function() {
                if($(this).attr('aria-level') > currentlevel) {
                    $(this).addClass('disabled_node');
                    // remove checks from levels below
                    $('#tree').jstree('deselect_node', '#'+this.id);

                } else if($(this).attr('aria-level') < currentlevel) {
                    // remove checks from levels above
                    $('#tree').jstree('deselect_node', '#'+this.id);
                }  
            });
        }

        if( data.action == 'deselect_node' && data.event && data.event.type === 'click'){    
            // if have other checked nodes at same level - do not enable children
            if ( $('#tree').find('li:not(#'+data.node.id+')[aria-level="'+currentlevel+'"][aria-selected="true"]').length>0 ) {
                return;
            }

            $('#tree').find('li').each( function() {
                if($(this).attr('aria-level') > currentlevel) {
                    $(this).removeClass('disabled_node');   
                }
            }); 
        }
    })
    .on('open_node.jstree', function(event, obj ) {
        $('#'+obj.node.id).find('li').each( function() {           
            if($(this).attr('aria-level') > currentlevel) {
                $(this).addClass('disabled_node');   
            }
        }); 
    })
    .jstree({
    "core" : {
        "data" : data,
        "multiple": true,
        "themes": {
            "url": true,
            "icons": true
        }
    },
    "checkbox" : {
      "three_state" : false
    },
  "conditionalselect" : function (node, event) {
      return !$('#'+node.id).hasClass('disabled_node');
    },
    "plugins" : [ "checkbox","conditionalselect" ]
 });

Thanks to nikolay-ermakov

Upvotes: 0

Nikolay Ermakov
Nikolay Ermakov

Reputation: 5061

You can use an attribute added by jsTree to all li elements - the aria-level attribute. It starts from 1 for root element and spans whole tree showing level for every node.

You will have to do this:

  1. add some events to jsTree object - changed event to disable visible nodes from next level and below and open_node to update status of to-be disabled nodes previously hidden (non-existent in the DOM till this moment to be exact)
  2. add conditionalselect plugin to disallow node selection if node is disabled

I kept the currently selected level in var currentlevel. You should check that it is kept local. Also you can surely optimize the code so it wouldn't repeat enable/disable functionality.

Check demo - JS Fiddle

Upvotes: 2

Related Questions