Drag and drop in Tree Grid heirarchies not performing as I expected?

Hi,  I hope you can help...

I'm trying to use the tree grid to show a four level deep set of nested and allow the user to drag and drop the data.  However, the data is strictly hierarchical meaning that items can only belong to their specific parent type.

I'm setting the data up using the children attribute as per this javascript code:

let data = props.source_data.map(stream => {
return {
id: 'stream_'+stream.id,
name: stream.name,
children: stream.stages.map(stage => {
return {
id: 'stage_'+stage.id,
name: stage.name,
//parentID: 'stream_'+stream.id,
children: stage.rooms.map(room => {
return {
id: 'room_'+room.id,
name: room.name,
status: room.status,
deadline: room.deadline,
estimated: room.estimated_units,
owner: room.owner,
//parentID: 'stage_'+stage.id,
children: room.tasks.map(task => {
return {
id: 'task_'+task.id,
name: task.name,
status: task.status,
deadline: task.deadline,
estimated: task.estimated_units,
owner: task.owner,
//parentID: 'room_'+room.id,
};
})
};
})
};
})
};
});

As you can see, a task belongs to a room, a room to a stage and a stage to a stream.

The tree grid is set up with this code:

<tree-grid-component id="ListTreeView" ref="ListTreeView" :dataSource="data" childMapping="children" :treeColumnIndex="1"
:selectionSettings='selectionSettings' :rowDropSettings='rowDropSettings'
:allowRowDragAndDrop='true' :rowDrop="rowDrop" :rowDrag="rowDrag">
<columns-directive>
<column-directive field='id' :isPrimaryKey='true' headerText='ID' textAlign='Right' width=70></column-directive>
<column-directive field='name' headerText='Name' textAlign='Left' width=200></column-directive>
<column-directive field='completed' headerText='Completed' textAlign='Right' format='yMd' width=90></column-directive>
<column-directive field='estimated' headerText='Estimated time' textAlign='Right' width=80></column-directive>
<column-directive field='deadline' headerText='Deadline' textAlign='Right' width=80></column-directive>
<column-directive field='owner' headerText='Owner' textAlign='Right' width=80></column-directive>
<column-directive field='status' headerText='Status' textAlign='Right' width=80></column-directive>
</columns-directive>
</tree-grid-component>

And I have a a draw and drop function where I try to work out what has happened so I can update the relevant data (just note the console logs as I show the output further down - as the specifics of what I'm doing in the function isn't that important for the issue I'm seeing):

rowDrop(args) {
console.log("From: " + args.fromIndex);
console.log("To: " + args.dropIndex);
console.log("data_id: " + args.data[0].taskData.id);

let treeGridobj = this.$refs.ListTreeView;
let records = treeGridobj.getCurrentViewRecords();
console.log(records);
let item = records[args.fromIndex];

let row_before = null;
let row_after = null;

let dest_parent_id = null;
let item_before_id = null;
let item_after_id = null;

const item_type = this.get_type(item.id);
console.log("Item type: " + item_type);
console.log("Position: " + args.dropPosition);
if (args.dropPosition === "middleSegment") {
console.log("Dropping onto: " + records[args.dropIndex].id);
console.log("Parent type: " + (item.parentItem ? this.get_type(item.parentItem.id) : "null"));
console.log(item);
if (item.parentItem && this.get_type(item.parentItem.id) === this.get_type(records[args.dropIndex].id)) {
console.log("Dropped onto right parent type");

row_before = null;
row_after = records[args.dropIndex].childRecords.length > 0 ? records[args.dropIndex].childRecords[0] : null;

dest_parent_id = records[args.dropIndex].id;
item_before_id = null;
item_after_id = row_after ? row_after.id : null;
} else {
console.log("Dropped onto wrong parent type");
// not allowed to be dropped here as wrong type so leaving *_ids as null...
}
} else if (args.dropPosition === "topSegment" || args.dropPosition === "bottomSegment") {
switch (args.dropPosition) {
case "topSegment":
row_before = args.dropIndex > 0 ? records[args.dropIndex - 1] : null;
row_after = args.dropIndex <= records.length ? records[args.dropIndex] : null;
break;
case "bottomSegment":
row_before = records[args.dropIndex];
row_after = args.dropIndex + 1 < records.length ? records[args.dropIndex + 1] : null;
break;
}

console.log("Row before: " + (row_before ? row_before.id : "null"));
console.log("Row after: " + (row_after ? row_after.id : "null"));

if (row_before) {
console.log("Checking row before");
// if same type above we can just insert
if (this.get_type(row_before.id) === item_type) {
if (row_before.childRecords.length === 0) {
// if same type and item before has no children - all good
console.log("Good position as beside a sibling (before)");
dest_parent_id = row_before.parentItem.id;
item_before_id = row_before.id;
item_after_id = row_after && this.get_type(row_after.id) === item_type ? row_after.id : null;
} else {
console.log("Can't go here as has children in the way....");
}
} else if (item.parentItem && this.get_type(row_before.id) === this.get_type(item.parentItem.id)) { // if same parent type we can just insert
console.log("Good position under parent");
dest_parent_id = row_before.id;
item_before_id = null;
item_after_id = row_after && this.get_type(row_after.id) === item_type ? row_after.id : null;
} else if (item.parentItem && this.get_type(row_before.id) !== this.get_type(item.parentItem.id)) {
console.log("Wrong type above... ie maybe a child of a sibling, so what's below....?");
console.log(this.get_type(row_after.id));
console.log(row_after);
if (this.get_type(row_after.id) === item_type) {
dest_parent_id = row_after.parentItem.id;
item_before_id = null;
item_after_id = row_after.childRecords.length > 0 ? row_after.childRecords[0].id : null;
console.log("Yes it is - it's the same type so insert in front of the after.... " + after);
} else {
console.log("Wrong position");
}
} else if (item.parentItem == null) {
console.log("Must be moving a stream");
console.log(row_after);
if (row_after === null || (row_after && this.get_type(row_after.id) === "stream")) {
dest_parent_id = null;
item_before_id = null; // ????? ######## THI IS WRONG AT THE MOMENT
item_after_id = row_after ? row_after.id : null;
} else {
console.log("Unable to move here");
}
} else {
console.log("ARGHHHH. Another condition.....");
}
} else {
if (row_after) {
console.log("Checking type to see if stream " + item_type);
if (item_type === "stream") {
dest_parent_id = null;
item_before_id = null;
item_after_id = row_after.id;
} else {
console.log("Not allowed to be here")
// not allowed
}
}
}
}


console.log("Sync...");
console.log("Item: " + item);
console.log("Type: " + item_type);
console.log("Bfor: " + (item_before_id ? item_before_id: null));
console.log("Aftr: " + (item_after_id ? item_after_id: null));
console.log("Prnt: " + (dest_parent_id ? dest_parent_id: null));

if (item_before_id !== null || item_after_id !== null || dest_parent_id !== null) {
console.log("axios");
switch (item_type) {
case 'room':
console.log("NOT Invoking sync");
/*axios.put("/strategy-room-sync-across-stages", {
strategy_id: this.strategy.id,
stage_id: this.get_id(dest_parent_id),
before_id: this.get_id(item_before_id),
room_id: this.get_id(item.id),
after_id: this.get_id(item_after_id)
}).then((response)=>{
response.data.forEach(room => {
/*let index = this.draggable_rooms.findIndex(r => r.id === room.id);
if (index !== -1) {
console.log("Moving " + this.draggable_rooms[index].strategy_stage_id + " : " + this.draggable_rooms[index].order);
console.log(" To " + room.strategy_stage_id + " : " + room.order);
Object.assign(this.draggable_rooms[index],room);
}
console.log("Got :" + room)
});
}).catch(err => {
console.error(err.response);
});*/
break;
default:
args.cancel = true;
break;
}
} else {
args.cancel = true;
}

This is the app running with some test data:



Now, sometimes the records behave as I expect... but others they don't.

For instance, if I drag room_3 from stage_1 to stage_3, the from an to index passed into the rowDrop function indicates that a middle Segment has been fired on the stage_3 row.  However, the room ends up nested under room_1 with the task_1,task_2 and task_3....

As per this screen shot:



And this is the output from the console as per the above function:



So, how do I ensure that the data goes into the right place?

As it should not be nested in with the tasks in the room_1, here:


I have tried adding the IDMapping and ParentIDMapping but that seemed to make no difference....

Any thoughts or insights would be most welcome?

Thank you,
Mark



5 Replies

PS Priyadarshan Selvan Syncfusion Team July 26, 2022 04:08 PM UTC

Hi Mark,


Thanks for contacting syncfusion support.


We were unable to reproduce the issue(Drag and drop in Tree Grid heirarchies not performing as expected) at our end while preparing a sample based on the shared details.


So, to proceed further we request you to get back to us with the following details.


  1. Share the product details version.
  2. If possible, share the issue reproducible sample.
  3. Share the video demo of your issue.


The provided information will be helpful to provide you response as early as possible. 


Regards,

Priyadarshan Selvan




MA Mark July 26, 2022 06:01 PM UTC

Hi , please find a screen recording attached.


These are the libraries I'm currently using:


"@inertiajs/inertia": "^0.10.1",
"@inertiajs/inertia-vue3": "^0.5.2",
"@inertiajs/progress": "^0.2.6",
"@popperjs/core": "^2.11.0",
"@syncfusion/ej2": "^20.2.36",
"@syncfusion/ej2-vue-base": "^20.2.36",
"@syncfusion/ej2-vue-buttons": "^20.2.36",
"@syncfusion/ej2-vue-dropdowns": "^20.2.36",
"@syncfusion/ej2-vue-gantt": "^20.2.36",
"@syncfusion/ej2-vue-kanban": "^20.2.38",
"@syncfusion/ej2-vue-navigations": "^20.2.36",
"@syncfusion/ej2-vue-treegrid": "^20.2.38",
"@tinymce/tinymce-vue": "^4.0.5",
"laravel-echo": "^1.11.3",
"notiwind": "^1.2.6",
"postcss-import": "^14.0.2",
"pusher": "^5.0.1",
"pusher-js": "^7.0.6",
"vue": "^3.2.26",
"vue-class-component": "^8.0.0-rc.1",
"vue-router": "^4.0.12",
"vue3-datepicker": "^0.3.1",
"vuedraggable": "^4.1.0",
"vuex": "^4.0.2"


This is the data:


[

  {

    "id": "stream_1",

    "name": "Default",

    "children": [

      {

        "id": "stage_5",

        "name": "KPIs",

        "children": []

      }

    ]

  },

  {

    "id": "stream_2",

    "name": "Team A",

    "children": [

      {

        "id": "stage_1",

        "name": "Stage A 1",

        "children": [

          {

            "id": "room_2",

            "name": "Room 2",

            "deadline": null,

            "estimated": null,

            "children": []

          },

          {

            "id": "room_3",

            "name": "Room 3",

            "deadline": null,

            "estimated": null,

            "children": []

          }

        ]

      },

      {

        "id": "stage_2",

        "name": "Stage A 2",

        "children": []

      }

    ]

  },

  {

    "id": "stream_3",

    "name": "Team B",

    "children": [

      {

        "id": "stage_3",

        "name": "Stage B 1",

        "children": [

          {

            "id": "room_1",

            "name": "Room 1",

            "deadline": null,

            "estimated": null,

            "children": [

              {

                "id": "task_1",

                "name": "Task 1",

                "status": 1,

                "estimated": null

              },

              {

                "id": "task_2",

                "name": "Task 2",

                "status": 1,

                "estimated": null

              },

              {

                "id": "task_3",

                "name": "Task 3",

                "status": 1,

                "estimated": null

              }

            ]

          }

        ]

      },

      {

        "id": "stage_4",

        "name": "Stage B 2",

        "children": []

      }

    ]

  }

]


<tree-grid-component id="ListTreeView" ref="ListTreeView" :dataSource="data" childMapping="children" :treeColumnIndex="1"
:selectionSettings='selectionSettings' :rowDropSettings='rowDropSettings'
:allowRowDragAndDrop='true' :rowDrop="rowDrop" :rowDrag="rowDrag" :actionComplete="onActionComplete">
<columns-directive>
<column-directive field='id' :isPrimaryKey='true' headerText='ID' textAlign='Right' width=70></column-directive>
<column-directive field='name' headerText='Name' textAlign='Left' width=200></column-directive>
<column-directive field='completed' headerText='Completed' textAlign='Right' format='yMd' width=90></column-directive>
<column-directive field='estimated' headerText='Estimated time' textAlign='Right' width=80></column-directive>
<column-directive field='deadline' headerText='Deadline' textAlign='Right' width=80></column-directive>
<column-directive field='owner' headerText='Owner' textAlign='Right' width=80></column-directive>
<column-directive field='status' headerText='Status' textAlign='Right' width=80></column-directive>
</columns-directive>
</tree-grid-component>

I hope this helps?


Thank you,

Mark



PS Pon Selva Jeganathan Syncfusion Team July 27, 2022 03:22 PM UTC

Hi Mark


Thanks for the update


We are working on this query with high priority. And we need time to validate the issue at our end. We will update further details by 29th July 2022. Until then we value your patience. In the meanwhile, we will contact you if any details are required.


Regards,  

Pon selva   





FS Farveen Sulthana Thameeztheen Basha Syncfusion Team August 11, 2022 05:46 AM UTC

Hi Mark,


Sorry for the delayed response.


On further validation, we have confirmed this issue as a bug and logged defect report for the same “RowDragandDrop not working properly with middlesegment”.  Thank you for taking the time to report this issue and helping us improve our product. At Syncfusion, we are committed to fixing all validated defects (subject to technical feasibility and Product Development Life Cycle) and including the defect fix in our August 4th week patch release(24th  August,2022). Until then we appreciate your patience.


You can now track the current status of your request, review the proposed resolution timeline, and contact us for any further inquiries through this Feedback link.

https://www.syncfusion.com/feedback/36722/rowdraganddrop-with-middlesegment-not-working-properly


Disclaimer :- Inclusion of this solution in the weekly release may change due to other factors including but not limited to QA checks and works reprioritization.


Regards,

Farveen sulthana T



FS Farveen Sulthana Thameeztheen Basha Syncfusion Team August 25, 2022 05:38 AM UTC

Hi Mark,


We appreciate your patience.   

We are glad to announce that fix for the issue
RowDragandDrop not working properly with middlesegment
has been rolled out in our patch release. We request you to update to our latest version "20.2.45" to resolve the problem.

Kindly get back to us for further assistance.


Regards,

Farveen sulthana T



Loader.
Up arrow icon