Conditional Row Drag and Drop in tree grid

I have a somewhat complex TreeGrid - which contains nested sections of disparate data. 

I have a requirement to support drag and drop within the grid, but have the following constraints I need to support:

  • Only certain rows can be dragged
    this can be achieved by cancelling the rowDragStartHelper (or rowDragStart??) event and by hiding the 'drag' icon for non-draggable rows icon via css so this sems achievable

  • Dragged rows can only be dropped in very specific locations - I need to give some indication that drop is not valid for records which contain certain data, and also cancel the drop if the user does attempt to drop

I'm also a little confused about the difference between the rowDragStartHelper and rowDragStart events, they both indicate a type of 'RowDragEventArgs' but at run-time I'm seeing quite different objects. 

3 Replies

GL Gowri Loganathan Syncfusion Team March 30, 2020 11:24 AM UTC

  
Hi Grant, 
 
Thanks for using Syncfusion Forum 

Query #1: Only certain rows can be dragged

We have achieved your requirement using rowDataBound event for hiding the drag icon of particular row and rowDragStartHelper event to cancel the drag action of particular row by giving args.cancel as true. Please refer the below code snippet and sample

Index.Html page 
<style> 
    . . . . . .  
    .e-row[aria-selected="true"] .e-customizedDragcell { 
        background-color: #e0e0e0;   // set the icon background color to hide it 
    } 
</style> 
Index.ts page 
. . .  . 
rowDataBound: function(args) {     // triggers before the rowdata get binded to treegrid 
    if (args.data.taskID == 1) {   // checking the condition here 
        args.row.querySelector('td').innerHTML = " "; 
        args.row.querySelector('td').className = "e-customizedDragcell";  // add classname to hide the dragicon in treegrid row when given condition satisfied 
    } 
}, 
rowDragStartHelper: function (args) { 
    if ( . . . .){  // give the condition here 
        args.cancel = 'true';       // cancel the drag operation of particular row 
    } 

},

 
Please refer the below help documentation 
 

Query# 2: Dragged rows can only be dropped in very specific locations - I need to give some indication that drop is not valid for records

We have achieved your requirement using rowDrop event by giving args.cancel as true in TreeGrid. In the below sample we have cancel the drop action for the parent row and we have given an alert message when we drop the dragged rows on the parent row.

Code snippet

. . . . . . 
rowDrop: function(args) { 
       var treeGridobj = document.getElementsByClassName("e-treegrid")[0].ej2_instances; 
       var data = treeGridobj[0].getCurrentViewRecords()[args.dropIndex]; 
       if(data.hasChildRecords){  // give your custom condition here 
           args.cancel = 'true' 
           alert("dropping disabled here"// alert message when dropping on parent row 
       }    

    },

. .. . . .

Please find the sample link below,

https://stackblitz.com/edit/sgcezb-duvaye

Query# 3 : Event difference in Treegrid row drag and drop  
The rowdragstart  get triggers when row element’s drag(move) starts. The rowdragstarthelper get Triggers when row element’s before drag(move). 
 
Also, refer the API link below. 
 
 
Please get back to us if you need more assistance 
 
Regards, 
Gowri V L. 
 



GE Grant EFive replied to Gowri Loganathan March 30, 2020 10:05 PM UTC


Thanks for the reply

For the answer to Query #2 - there's 1 important part (for me) missing from your solution, my question 'I need to give some indication that drop is not valid for records'. 
Simply cancelling the drop is not a great user experience.

Ideally - I'd like to achieve something like the indicator below - but I've no idea how to enable that programatically (and for my purposes, this decision is based on properties of the data of the potential drop location):

              


For Query #3 - I have indeed read the documentation, and I think it's severely lacking. This is compounded by the fact that the type declarations of these callback arguments have very little relationship to the actual runtime objects.

For example the rowDragStartHelper callback specifies a type of:

interface RowDragEventArgs {
    rows?: Element[];
    target?: Element;
    draggableType?: string;
    data?: Object[];
    fromIndex?: number;
    dropIndex?: number;
    originalEvent?: object;
    cancel?: boolean;
}

however, the runtime object for this callback has the following properties:

{
    selectedRow: [tr.e-row.e5-team-profiler-user-row],
    dragelement: div.e-icons.e-rowcelldrag.e-dtdiagonalright.e-icon-rowdragicon,
    cloneElement: div.e-cloneproperties.e-draganddrop.e-grid.e-dragclone.e-movecur,
    cancel: false,
    data: [{…}],
    name: "rowDragStartHelper",
}

This is pretty much true for all of the callbacks...

I would really like to override the default drag element UI with my own - but there's no indication of how to do that (I was thinking that I could possibly override the dragelement or cloneElement properties but neither of those could be successfully overridden in my tests)


TS Thavasianand Sankaranarayanan Syncfusion Team March 31, 2020 11:38 AM UTC

Hi Grant, 
 
Query 2: There's 1 important part (for me) missing from your solution, my question 'I need to give some indication that drop is not valid for records'.  
 
We have achieve your requirement by using the rowDrag event of TreeGrid. In the below cod example we have shown icon in the cloned element for the drop target which is not a valid record. 
 
[index.ts] 
 
let treegrid: TreeGrid = new TreeGrid( 
  { 
    dataSource: dragData, 
     
    . . . 
     
    rowDrag: function (args) { 
       
      let rowEle: Element = args.target ? args.target.closest('tr') : null; 
      let rowIdx: number = rowEle ? (rowEle as HTMLTableRowElement).rowIndex : -1; 
      let currentData: ITreeData = this.getCurrentViewRecords()[rowIdx]; 
      if (rowIdx !== -1) { 
        if (currentData.hasChildRecords) 
          this.rowDragAndDropModule.addErrorElem(); 
      } 
 
    }, 
 
    treeColumnIndex: 1, 
    columns: [ 
 
           . . . 
 
    ], 
  }); 
treegrid.appendTo('#TreeGrid'); 
 
 
 
Refer the help documentation. 
 
 
Query 3: Have indeed read the documentation, and I think it's severely lacking. This is compounded by the fact that the type declarations of these callback arguments have very little relationship to the actual runtime objects. 
 
We have checked the with your given details and we are able to reproduce the issue from our end. Based on your suggestion we will modify the documentation for the rowDragStartHelper events in TreeGrid. 
 
We can customize the clone element in the rowDragStart event of TreeGrid. In the below code example we have modified the font family of the dragged or cloned element. 
 
[index.ts] 
 
let treegrid: TreeGrid = new TreeGrid( 
  { 
    dataSource: dragData, 
     
     . . . . 
    
    rowDragStart: function (args) { 
 
      args.rows[0].classList.add('e-dragclonerow'); 
    }, 
 
    treeColumnIndex: 1, 
    columns: [ 
 
               . ..  
    ], 
  }); 
treegrid.appendTo('#TreeGrid'); 
 
------------------------------------------------------------------------------------------------------ 
[index.html] 
 
<style> 
 
    .e-dragclonerow { 
 
        font-family: fantasy; 
    } 
 
</style> 
 
 
Refer the help documentation. 


We have prepared a sample with both the solution implemented in the following stackblitz link. 
 

If the above customization meets your requirements or you need to change that cloned element in a different way. If so, please share your requirement to change or alter the cloned element.  

Regards, 
Thavasianand S. 


Loader.
Up arrow icon