Grid With Locked Columns and Drag and Drop

1 Answer 551 Views
Grid
Lee
Top achievements
Rank 2
Bronze
Bronze
Bronze
Lee asked on 17 Aug 2022, 10:19 PM | edited on 19 Aug 2022, 04:29 PM

I have a grid with the drag and drop feature and locked columns. I have a need for the row to be dragged up and down in the grid. I found an article on your site but it does not really work, even in your own Dojo. It only allows dragging to the top and should allow dragging anywhere. It doesn't leave a gap on the unlocked side of the table as would be expected. I would like it to clone the existing row and use that as a placeholder on both sides of the grid. Also, the column widths are not preserved.

Below is a link to the article: https://docs.telerik.com/kendo-ui/knowledge-base/grid-drag-drop-with-locked-columns

Article

Update:

Here is some code that I currently have which fixes the issue with the column widths and the dragging to the top only. It doesn't address the issue with the placeholders though.

function enableKendoGridLockedDND(gridElement) {
    if (!gridElement) {
        gridElement = ".k-grid";
    }
    let grid = $(gridElement).data("kendoGrid");
    if (!grid.lockedTable) {
        return false;
    }
    let gridWidth = $(gridElement).width();
    let lockedWidth = $(gridElement).find(".k-grid-header-locked").width() || 0;
    let unlockedWidth = $(gridElement).find(".k-grid-header-wrap table").width() || 0;
    let tableWidth = lockedWidth + unlockedWidth + 2;
    grid.lockedTable.kendoSortable({
        axis: "y",
        filter: ">tbody >tr",
        hint: function(element) {
            var unlockedPortion = grid.table.find("tr[data-uid=" + element.data("uid") + "]").children();
            let table = $(`<div style="overflow: hidden; width: ${gridWidth}px;"><table style="background: whitesmoke; width: ${tableWidth}px;" class="k-grid k-widget"></table></div>`);
            let colgroups = $(gridElement).find(".k-grid-header colgroup");
            let colgroupWidths = [];
            $.each(colgroups, function (index, group) {
                $.each($(group).children(), function (index2, child) {
                    colgroupWidths.push($(child).css("width"));
                });
            });
            table.find("table").append(element.clone().append(unlockedPortion));
            $.each(table.find("td"), function (index, col) {
                $(col).css("width", colgroupWidths[index]);
            });
            console.log(table);
            table.css("opacity", 0.7);
            return table;
        },
        cursor: "move",
        placeholder: function (element) {
            return element.clone().css({
                "opacity": 0.3,
                "border": "1px dashed #000000"
            });
        //    console.log("placeholder", element);
        //    var unlockedRow = grid.table.find("tr[data-uid=" + element.data("uid") + "]");
        //    var unlockedPortion = unlockedRow.children();
        //    console.log(element);
        //    return element;
        //   // return $(`<tr class="w-100 grid-placeholder" style="background: green;"><td>Hello World</td><td></td><td></td></tr>`);
        },
        //move: function (e) {
        //    let event = e.draggableEvent;
        //    console.log("event", event);
        //    let item = e.item;
        //    let itemUID = $(item).data("uid");
        //    console.log("UID", itemUID);
        //    console.log("item", item);
        //    let unlockedDraggingRow = grid.table.find("tr[data-uid=" + item.data("uid") + "]").children();
        //    console.log(unlockedDraggingRow);
        //    console.log("clone", unlockedDraggingRow.clone());
        //    let target = e.target;
        //    let unlockedTargetRow = grid.table.find("tr[data-uid=" + target.data("uid") + "]");
        //    $(gridElement).find("tr.d-none").removeClass("d-none");
        //    $(gridElement).find("#dragPlaceholderRow").remove();
        //    $(grid.table.find("tr[data-uid=" + target.data("uid") + "]")).before(`<tr id="dragPlaceholderRow"><td colspan="6">Yo!</td></tr>`);
        //    $(unlockedTargetRow).addClass("d-none");
        //},
        end: function (e) {
            let skip = grid.dataSource.skip() || 0;
            let newIndex = e.newIndex + skip;
            let dataItem = grid.dataSource.getByUid(e.item.data("uid"));
            grid.dataSource.remove(dataItem);
            grid.dataSource.insert(newIndex, dataItem);
        },
        change: function(e) {
            let skip = grid.dataSource.skip() || 0;
            let newIndex = e.newIndex + skip;
            let oldIndex = e.oldIndex + skip;
            let data = grid.dataSource.data();
            let dataItem = grid.dataSource.getByUid(e.item.data("uid"));
            console.log("skip", skip);
            console.log("newIndex", newIndex);
            grid.dataSource.remove(dataItem);
            grid.dataSource.insert(newIndex, dataItem);
          }
        });
}

Here is what the change event returns:


action: "remove"
draggableEvent: {originalEvent: MouseEvent, type: 'mouseup', target: span.k-icon.k-i-reorder, currentTarget: fn.init(1), isDefaultPrevented: ƒ, …}
isDefaultPrevented: ƒ ()
item: fn.init [tr.k-alt.k-master-row]
newIndex: -1
oldIndex: 1
preventDefault: ƒ ()
sender: init {element: fn.init(1), _events: {…}, options: {…}, draggable: init, draggedElement: fn.init(1), …}
_defaultPrevented: false

1 Answer, 1 is accepted

Sort by
0
Lee
Top achievements
Rank 2
Bronze
Bronze
Bronze
answered on 19 Aug 2022, 05:00 PM | edited on 19 Aug 2022, 05:10 PM

So, I solved this by creating a function that can be called after creating a draggable grid with locked columns. Unfortunately the grid's rowReorder event is never called. 

Like this:

let myGrid = $("#myGrid").kendoGrid({
   reorderable: {
      rows: true,
   },
   rowReorder: function(ev) {
     // do something
   },
   // rest of options
}).data("kendoGrid");
enableKendoGridLockedDND("#myGrid");

Here is the function:

function enableKendoGridLockedDND(gridElement) {
    if (!gridElement) {
        gridElement = ".k-grid";
    }
    let grid = $(gridElement).data("kendoGrid");
    if (!grid.lockedTable) {
        return false;
    }
    let gridWidth = $(gridElement).width();
    let lockedWidth = $(gridElement).find(".k-grid-header-locked").width() || 0;
    let unlockedWidth = $(gridElement).find(".k-grid-header-wrap table").width() || 0;
    let tableWidth = lockedWidth + unlockedWidth + 2;
    let placeholderPosition = null;
    grid.lockedTable.kendoSortable({
        axis: "y",
        filter: ">tbody >tr",
        hint: function(element) {
            let unlockedPortion = grid.table.find("tr[data-uid=" + element.data("uid") + "]").children();
            let hint = $(`<div style="overflow: hidden; width: ${gridWidth}px;"><table style="background: whitesmoke; width: ${tableWidth}px;" class="k-grid k-widget"></table></div>`);
            let colgroups = $(gridElement).find(".k-grid-header colgroup");
            let colgroupWidths = [];
            $.each(colgroups, function (index, group) {
                $.each($(group).children(), function (index2, child) {
                    colgroupWidths.push($(child).css("width"));
                });
            });
            hint.find("table").append(element.clone().append(unlockedPortion.clone()));
            $.each(hint.find("td"), function (index, col) {
                $(col).css("width", colgroupWidths[index]);
            });
            hint.css("opacity", 0.7);
            return hint;
        },
        cursor: "move",
        placeholder: function (element) {
            var unlockedRow = grid.table.find("tr[data-uid=" + element.data("uid") + "]");
            $(unlockedRow).before($(unlockedRow).clone().attr("data-uid", "").addClass("k-hover unlocked-placeholder"));
            $(unlockedRow).hide();
            let placeholder = element.clone();
            $(placeholder).attr("data-uid", "");
            return placeholder;
        },
        move: function (e) {
            //Set positions
            let lastPosition = placeholderPosition;
            placeholderPosition = this.indexOf(this.placeholder);
            let itemPosition = this.indexOf(e.item);
            let targetPosition = this.indexOf(e.target);

            //Get Elements
            let unlockedDraggingRow = $(gridElement).find(".k-grid-content tr.unlocked-placeholder");
            let targetElement = $(gridElement).find(".k-grid-content tr[data-uid=" + e.target.data("uid") + "]");

            //Find direction of move
            let movingUp = false; 
            if (lastPosition === null) {
                if (itemPosition > targetPosition) {
                    movingUp = true;
                }
            } else {
                if (lastPosition > placeholderPosition) {
                    movingUp = true;
                }
            }

            //Move the unlocked row
            if (movingUp) {
                targetElement.before(unlockedDraggingRow);
            } else {
                targetElement.after(unlockedDraggingRow);
            }
        },
        change: function (e) {
            let skip = grid.dataSource.skip() || 0;
            let newIndex = e.newIndex + skip;
            let dataItem = grid.dataSource.getByUid(e.item.data("uid"));
            grid.dataSource.remove(dataItem);
            grid.dataSource.insert(newIndex, dataItem);
        },
        start: function () {
            placeholderPosition = null;
        }
    });

}
Nikolay
Telerik team
commented on 22 Aug 2022, 02:17 PM

Hi Lee,

Thank you so much for sharing this solution with the community. I believe it will be helping others facing the same scenario.

Regarding the rowReorder event not firing, you need to manually trigger it:

change: function (e) {
                let skip = grid.dataSource.skip() || 0;
                let newIndex = e.newIndex + skip;
                let dataItem = grid.dataSource.getByUid(e.item.data("uid"));
                grid.dataSource.remove(dataItem);
                grid.dataSource.insert(newIndex, dataItem);
                grid.trigger("rowReorder");
              },

Regards,

Nikolay

Tags
Grid
Asked by
Lee
Top achievements
Rank 2
Bronze
Bronze
Bronze
Answers by
Lee
Top achievements
Rank 2
Bronze
Bronze
Bronze
Share this question
or