2

I have a question. I created a TreeView and tried to bind the drag'n'drop, everything works, the TreeItem can be moved. BUT. If you expand any TreeItem and try to drag it, then all its child TreeItems will move with it.

How to make only one TreeItem drag'n'drop, without its child TreeItems????

My guess is I need to access the inner component of the item tree. I also don't know how to do this.

My Code:

export const PathTreeItem = (props: PathTreeItemProps) => {
  const [obj, setObj] = useState<TreeItemType[] | undefined>(undefined)
  const [isCurrentRequest, setIsCurrentRequest] = useState(false)

  const [{ isDragging }, drag] = useDrag({
    item: { type: props.obj.description || 'asd' },
    canDrag: true,
    collect: (monitor: DragSourceMonitor) => ({
      isDragging: monitor.isDragging(),
    }),
  })

  const treeItemStyle = useMemo(
    () => ({
      opacity: isDragging ? 0.4 : 1,
    }),
    [isDragging]
  )

  useEffect(() => {
    if (isCurrentRequest && props.obj.parameter_type === 'ABC') {
      APIs.get(props.obj.name)
        .then(res => {
          setObj(res.data)
        })
        .catch(err => {=
          console.error('Error ', err)
        })
    }
  }, [isCurrentRequest])

  const handleLabelCLick = useCallback(event => {
    console.log(event)
    setIsCurrentRequest(!isCurrentRequest)
  }, [])

  return (
    <TreeItem
      ref={drag}
      style={treeItemStyle}
      nodeId={props.index}
      label={props.obj.description}
      onLabelClick={handleLabelCLick}
    >
      {props.obj.parameter_type === 'ABC' ? (
        obj ? (
          obj.map((value, index) => (
            <PathTreeItem
              key={props.keyIndex * 100 + index}
              keyIndex={index}
              index={`${props.index}.${index}`}
              obj={value}
            />
          ))
        ) : (
          <div></div>
        )
      ) : null}
    </TreeItem>
  )
}
Liquinder
  • 31
  • 1
  • 6
  • You've got me curious, what's your use case for not dragging child items with the parent node? Are you wanting the child nodes to automatically move up one level when the parent is dragged else where in the tree? – EspressoBeans Jan 21 '21 at 16:35
  • @EspressoBeans . In my case. There is a TreeItem, if you look in a browser through f12, it will be composed of 2 div-elements. I would like to drag not the TreeItem itself, but only 1 of these div items – Liquinder Jan 22 '21 at 06:54
  • @EspressoBeans . At the moment, I have not come up with a way to implement what I want. You ask me why do I need this? – Liquinder Jan 22 '21 at 07:14
  • @EspressoBeans . With the current implementation of my TreeView, if 1 TreeItem contains a sufficiently large number of children, then of the tree, then when dragging the TreeItem, all its children are visually dragged along with it (this is provided that TreeItem are expanded and its children are visible, if it is collapsed, then everything works well). if the children are visible, then when dragging, a huge picture is obtained that stretches behind the mouse, and I want only 1 to drag the TreeItem itself without its children. – Liquinder Jan 22 '21 at 07:17
  • Would you be able to set the `expanded` prop to `false` on the parent node when a drag event starts on that node? Here are some related links: https://stackoverflow.com/questions/57742324/how-to-programmatically-expand-or-collapse-tree-item-in-material-ui, https://codesandbox.io/s/material-demo-forked-sre9c?file=/demo.js – EspressoBeans Jan 22 '21 at 16:22
  • Similar problem here. Setting `expanded` to `false` as @EspressoBeans suggested might help with the child items, but even then, the user would typically expect that only the tree item label / component is moved - and not the entire tree item (including e.g. any expand / collapse icons). Sounds like a minor detail, but really makes a difference to the look & feel of the UI. – ssc Jul 19 '22 at 20:37

1 Answers1

1

I have solved that problem by not dragging the TreeItem itself, but a custom component attached to it as its label attribute. Unfortunately, the solution currently only works in Firefox, not in Chrome or Safari:

const CustomItem = () => {
  return (
    // custom item components (Box, Typography, etc.)
  );
}

const DraggableCustomItem = () => {
  const [{ isDragging }, drag] = useDrag({
    collect: (monitor: DragSourceMonitor) => ({
      isDragging: monitor.isDragging()
    }),
    type: 'CustomItem'
  })
  
  return (
    <div ref={drag} style={{ opacity: isDragging ? 0.5 : 1}}>
      <CustomItem/>
    </div>
  )
}

const TreeViewDraggableCustomItem = () => {
  return (
    <TreeView>
      <TreeItem key    = { '1' }
                nodeId = { '1' }
                label  = { <DraggableCustomItem/> }>
    </TreeView>
  );
}

See also related SO question, example sandbox and github comment.

ssc
  • 9,528
  • 10
  • 64
  • 94