25

I have 37 different node types. I am trying to implement drag and drop. This works but I need to restrict exactly which types can be dragged and where they can be dropped. I can't find any useful information in the docs unfortunately (http://www.jstree.com/documentation).

So far I have tried three methods:

first: defining return values of true or false in the drag_check callback depending on the node type:

$("#demo1").jstree({
    "dnd" : {
        "drag_check" : function () {

second: binding to the prepare_move.jstree event and returning true or false values depending on the node type:

.bind("prepare_move.jstree", function (e, data) {
   if (data.rslt.o.attr("typ") === "tpop") {

third: using the types plugin and defining valid children there:

$("#tree").jstree( {
    "types": {
        "type_attr": "typ",
        "valid_children": ["ap_ordner_pop", "ap_ordner_apziel", "ap_ordner_erfkrit", "ap_ordner_apber", "ap_ordner_ber", "ap_ordner_beob", "iballg", "ap_ordner_ibb", "ap_ordner_ibartenassoz"],
        "types": {
        "ap_ordner_pop": {
            "valid_children": "pop"
        },
        "pop": {
            "valid_children": ["pop_ordner_tpop", "pop_ordner_popber", "pop_ordner_massnber"],
            "new_node": "neue Population"
        },
        "pop_ordner_tpop": {
            "valid_children": "tpop"
        }

But I can still drop most nodes nearly anywhere. How must this be done? Or can you point me to a good example?

Help is much appreciated.

Alex
  • 2,117
  • 5
  • 28
  • 36

2 Answers2

55

For those of you looking for answers using jstree v3. The crrm plugin has been removed, and instead you will want to use 'check_callback'.

In my case all I wanted to do was stop child items from being dragged into other child items. There may be a better way to do this but after hours of little progress, this is what worked for me.

I believe you also need to set 'check_while_dragging' dnd option to true in order to trigger 'check_callback' while dragging.

Here's my jsTree initialisation:

$("#jsTree").jstree({
            'core': {
                'data': window.treeData,
                'themes': {
                    'icons': false
                },
                'check_callback': function(operation, node, node_parent, node_position, more) {
                    // operation can be 'create_node', 'rename_node', 'delete_node', 'move_node' or 'copy_node'
                    // in case of 'rename_node' node_position is filled with the new node name

                    if (operation === "move_node") {
                        return node_parent.original.type === "Parent"; //only allow dropping inside nodes of type 'Parent'
                    }
                    return true;  //allow all other operations
                }
            },
            "state": { "key": "<%=Request.QueryString["type"]%>_infotree" },
            "dnd": {
                check_while_dragging: true
            },
            "plugins": ["state", "dnd", "types"]
        })
Tonic
  • 566
  • 1
  • 9
  • 13
  • 2
    This didn't quite work the way I expected. When I return false from the callback, it does prevent the source item from being added to the parent item. However, I had expected to see a "red X" while hovering over the target node to indicate that it was not allowed. Instead what happens is I see a green check mark which makes it seem like I can drag and drop on the target and when I do drop it nothing happens. Not wanting to spend too much time on it, I just added an alert that says "Drag and drop onto this node is not allowed" when the event occurs. – izmaxx Jan 27 '15 at 19:04
  • 1
    Thanks for the info on version 3. I'm new to this and I've had a hard time with figuring out what is available in different versions. – Sean Lynch Mar 06 '15 at 19:50
  • @izmaxx, I noticed that if u try to drag the node before the 1st item in the list, nothing happens. But if u drag an item after the 1st item in the list, the item is moved. In order get around this bug, I make use of the sort plugin and sort by an "order" property, and then process the newly ordered list on my server, and send the new ordered list back to the UI. When submitted to the server, then item is inserted the item at the front of the list IF the item was dragged on to a parent. Then I send the new order back to the front end and rewrite the tree – Paul Preibisch Jan 14 '16 at 04:17
  • for me, the check_callback needs to async call an ajax function which will return a promise to decide "true" or "false", but according to API this callback function only asks for true or false, rather than promise. how should I handle this? – ROROROOROROR Jun 26 '16 at 13:55
  • 1
    @izmaxx or @tonic, did you ever figure out how to make the "red X" change to the "green ✓" using `check_callback()` or some other means? – daniel.caspers Jul 19 '16 at 18:20
  • 1
    @daniel.caspers setting check_while_dragging to true gave me to the red cross. – Kaustubh Jan 31 '17 at 07:12
  • This was exactly what I needed, `move_node` helped in identifying the node type to allow or restrict drop and `copy_node` helped to make ajax call to update backend. thanks.. – Anupam Apr 19 '20 at 10:53
12

On the target(s) you would need to check if you are allowed to drop an object there. It seems you have some mechanism to smell the object as you indicated with:

 if (data.rslt.o.attr("typ") === "tpop")

That's good. Use that technique to discriminate one object type from another when performing a multitree operation. In the example below I use class names from source and target to do my own unique "smell test". Don't copy and paste or you'll get confused. You need to use your own type of test to accept/reject a drag and drop from one tree to another. All of my testing is done in the crrm check_move function.

.jstree({
 "crrm" : {
    input_width_limit : 200,
    move : {
        always_copy     : "multitree", // false, true or "multitree"
        open_onmove     : false,
        default_position: "last",
        check_move      : function (m) { 
                            if(!m.np.hasClass("someClassInTarget")) return false;
                            if(!m.o.hasClass("someClassInSource")) return false;
                            return true;
                          }
    }
 },
 "dnd" : {
    copy_modifier   : $.noop,
    drop_target     : ".someWrapperClassInSource",
    drop_check      : function (data) { return true; },
    drop_finish     : function (data) {
                            $.jstree._reference(this.get_container()).remove($(data.o));
                      },
    drag_target     : ".someClassInSource",
    drag_finish     : function (data) {;},
    drag_check      : function (data) { return { after : false, before : false, inside : true }; }
 },
MMeah
  • 1,032
  • 1
  • 9
  • 18
  • yeah, crrm's check_move works! Thanks a lot for your help, MMeah. I wish the documentation would be more clear on this point – Alex Jun 17 '12 at 09:03
  • yeah, the doc isn't that clear. You have to look at the source code to find this info out. Search the source for: "check_move" – MMeah Jun 17 '12 at 22:56
  • Have experienced the same thing with jsTree docs - they aren't as clear as they could be. +1 for `check_move` – scrowler Dec 03 '13 at 01:13
  • 1
    Been using jsTree v3 for a couple of weeks and don't like the documentation myself. I smell an Internet Explorer. – Code Monkey Feb 10 '14 at 19:47