Kendo TreeView Move Parent nodes to change the Sort Order but not allow a Parent to be dragged under a Child node

I have Kendo TreeView in which parent nodes have children nodes.

Rules that I want are that a user can

  1. Drag parent node above or below the current position , thus change the sort order
  2. Not allow a parent to be dragged onto another parent node
  3. Not allow a parent to be dragged onto any child node
  4. DO allow a child node item to be dragged under another parent node

I certainly prefer javascript or jquery

This code simply prevents all parent nodes from being dragged and thus it is not want I am wanting. Anyone have any samples on this?

 $(".k-treeview").data("kendoTreeView").bind("dragstart", function (e) {
    if ($(e.sourceNode).parentsUntil(".k-treeview", ".k-item").length == 0) {
       e.preventDefault();
    }
});

UPDATE from answer

Seems that almost all the code it working correcting from the answer if I place it in my $(document).ready(function() { ...

But If I place that code under the onDrop is does not get called up.

e.g.

  var treeview = $("#treeview").kendoTreeView({
                                    expanded: true,
                                    dragAndDrop: true,
                                    select: onSelect,
                                    loadOnDemand: false,
                                    dataSource: homogeneous,
                                    dataTextField: "ReportGroupName",
                                    template: kendo.template($("#treeview-template").html()) //,
                                    ,
                                    onDrop: function(e) {
                                        kendoTreeView = $(".k-treeview").data("kendoTreeView");
                                        kendoTreeView.bind("drag", function (e) {

                                            //Check if we're trying to add the node as a child
                                            var dropAsChild = $(e.dropTarget).hasClass("k-in k-state-hover");

                                            var sourceDataItem = kendoTreeView.dataItem(e.sourceNode);
                                            var destinationDataItem = kendoTreeView.dataItem(e.dropTarget);

                                            if ($(e.sourceNode).is(e.dropTarget)) {
                                                //Dropping on itself
                                                e.setStatusClass("k-denied");
                                            } else if (destinationDataItem && !dropAsChild) {
                                                //Dropping as a sibling... that's ok if it's the same parent
                                                if (sourceDataItem.parent().uid != destinationDataItem.parent().uid) {
                                                    //Not the same parent
                                                    e.setStatusClass("k-denied");
                                                }
                                            } else {
                                                e.setStatusClass("k-denied");
                                            }
                                        });
                                    }

                                }).data("kendoTreeView");

IMAGE
Here is an image red arrow is pointing at child that I was to move to another parent ( to be a child of that parent with blue arrow)

enter image description here

4 thoughts on “Kendo TreeView Move Parent nodes to change the Sort Order but not allow a Parent to be dragged under a Child node”

  1. The problem with the dragstart event is that it won’t provide you the drop target as it’s to early in the event sequence.

    The best way to do achieve this would be to deny the drop action based on the source and destination node. You can do this by calling the setStatusClass (with a k-denied) on the event object passed to the drag event.

    var treeview = $("#treeview").kendoTreeView({
        expanded: true,
        dragAndDrop: true,
        select: onSelect,
        loadOnDemand: false,
        dataSource: homogeneous,
        dataTextField: "ReportGroupName",
        template: kendo.template($("#treeview-template").html()),
        drag: function (e) {
            //Check if we're trying to add the node as a child
            var kendoTreeView = $("#treeview").data("kendoTreeView");
            var dropAsChild = $(e.dropTarget).hasClass("k-in k-state-hover");
    
            var sourceDataItem = kendoTreeView.dataItem(e.sourceNode);
            var destinationDataItem = kendoTreeView.dataItem(e.dropTarget);
    
            if ($(e.sourceNode).is(e.dropTarget)) {
                //Dropping on itself
                e.setStatusClass("k-denied");
            } else if (destinationDataItem && !dropAsChild) {
                //Dropping as a sibling... that's ok if it's the same parent
                if (sourceDataItem.parent().uid != destinationDataItem.parent().uid) {
                    //Not the same parent
                    e.setStatusClass("k-denied");
                }
            } else {
                e.setStatusClass("k-denied");
            }
        }
    }).data("kendoTreeView");
    

    I can’t test the code above right now so they may be some error… I’m sure you’ll still understand the logic behind it.

    Reply
  2. We can check e.statusClass in drag event. So cancel dragging if element is adding as a child.

    drag: function (e) {
      //Check if are we adding node as a child
      if(e.statusClass == "i-plus") { 
        e.setStatusClass("k-i-cancel"); //Cancel drop
      }
    }
    

    In my kendo treeview version classes naming was different, please read below class names and define class names as per your kendo version.

    As per API reference of kendoTreeView drag event

    Pre-defined status classes are:

    k-insert-top

    • Indicates that the item will be inserted on top.

    k-insert-middle

    • Indicates that the item will be inserted in the
      middle.

    k-insert-bottom

    • Indicates that the item will be inserted at
      the bottom.

    k-add

    • Indicates that the item will be added/appended.

    k-denied

    • Indicates an invalid operation. Using this class will
      automatically make the drop operation invalid, so there will be no
      need to call setValid(false) in the drop event.

    This is most important:-

    Please note that from version 2016.3.914 the naming convention for pre-defined status classes is k-i-className. Since version 2017.1.118 the following status classes are used: k-i-insert-up, k-i-insert-down, k-i-insert-middle, k-i-plus, k-i-cancel.

    Note that status classes are returned without the k- prefix by e.statusClass, but this prefix is required when setting a predefined status class via e.setStatusClass. A prefix is not required if setting a custom status CSS class.

    Reply

Leave a Comment