Closed GVSSri closed 3 months ago
I think you can use the canDrop prop. If you want to prevent moving the child node to another parent, just return true only if the parent's ID is the same.
canDrop={(tree, { dragSource, dropTargetId }) => {
if (dragSource?.parent === dropTargetId) {
return true;
}
}}
I tried but its not working as expected. My req is to maintain the hierarchy level during drag and drop, meaning a node can only be moved within its current level (siblings), Any help much appreciated
@GVSSri
Okay, if you just want to move nodes within their current level, I think you have to create a custom handleDrop callback function. You can sort nodes within that function.
this is a sample code
sample data
const initialData: NodeModel[] = [
{
id: 1,
parent: 0,
droppable: true,
text: "Folder 1",
},
{
id: 2,
parent: 1,
droppable: true,
text: "File 1-1",
},
{
id: 3,
parent: 1,
droppable: true,
text: "File 1-2",
},
{
id: 4,
parent: 1,
droppable: true,
text: "File 1-3",
},
{
id: 5,
parent: 1,
droppable: true,
text: "File 1-4",
},
{
id: 6,
parent: 1,
droppable: true,
text: "File 1-5",
},
{
id: 7,
parent: 1,
droppable: true,
text: "File 1-6",
},
{
id: 8,
parent: 1,
droppable: true,
text: "File 1-7",
},
{ id: 9, parent: 0, droppable: true, text: "Folder 2" },
];
sort function and custom handleDrop function
function moveElement<T>(array: T[], fromIndex: number, toIndex: number): T[] {
const element = array.splice(fromIndex, 1)[0];
array.splice(toIndex, 0, element);
return array;
}
const handleDrop = (_: NodeModel[], { dragSource, dropTarget }: DropOptions) => {
const dragSourceIndex = treeData.findIndex((item) => item.id === dragSource?.id);
const dropTargetIndex = treeData.findIndex((item) => item.id === dropTarget?.id);
setTreeData((prev) => moveElement(prev, dragSourceIndex, dropTargetIndex));
};
usage as component props
<DndProvider backend={MultiBackend} options={getBackendOptions()}>
<Tree
tree={treeData}
rootId={0}
onDrop={handleDrop}
sort={false}
canDrop={(_, { dragSource, dropTarget }) => {
if (dragSource?.id === dropTarget?.id) {
return false;
}
if (dragSource?.parent === dropTarget?.parent) {
return true;
}
return false;
}}
render={(node, { depth, isOpen, onToggle }) => (
<div key={node.id} style={{ marginLeft: depth * 10 }}>
{node.droppable && (
<span onClick={onToggle}>{isOpen ? "[-]" : "[+]"}</span>
)}
{node.text}
</div>
)}
/>
</DndProvider>
I hope it was helpful to you. Thank you
@GVSSri To allow only sorting of nodes in the same hierarchy, the following API must be specified.
<Tree
tree={treeData}
rootId={0}
render={(node, { depth, isOpen, onToggle }) => (
<CustomNode
node={node}
depth={depth}
isOpen={isOpen}
onToggle={onToggle}
/>
)}
dragPreviewRender={(monitorProps) => (
<CustomDragPreview monitorProps={monitorProps} />
)}
onDrop={handleDrop}
classes={{
root: styles.treeRoot,
draggingSource: styles.draggingSource,
placeholder: styles.placeholderContainer,
}}
sort={false}
insertDroppableFirst={false}
canDrop={(tree, { dragSource, dropTargetId, dropTarget }) => {
return dragSource?.parent === dropTargetId;
}}
dropTargetOffset={10}
placeholderRender={(node, { depth }) => (
<Placeholder node={node} depth={depth} />
)}
initialOpen={true}
/>
I think this Codesandbox will be helpful. https://codesandbox.io/p/sandbox/issue225-pd3536?file=%2Fsrc%2FApp.tsx%3A31%2C26
if you can't solve your problem yet, please reopen this issue.
thank you.
Is any other way to restrict moving the child to another parent. Want to maintain the hierarchy level within we can perform drag and drop
Please help on this