react-beautiful-dnd icon indicating copy to clipboard operation
react-beautiful-dnd copied to clipboard

How to prevent drag/drop behaviour from being triggered from within Draggable?

Open zachsa opened this issue 4 years ago • 9 comments

Using

<Draggable>
  <div>
    ... lots of children
    <div id="slider">
  </div>
</Draggable>

I would like to be able to stop the drag and drop from happening when div#slider is interacted with. To do this, my current idea is to wrap div#slider inside a element that stops event propagation. So:

Expected behavior

const handler = e => e.stopPropagation()
<Draggable>
  <div onClick={handler} onMouseDown={handler} ... etc.>
    <div id="slider" />
  </div>
</Draggable>

But having tried handling quite a number of different events at this point, I can't figure out which events are propagating. Surely there must be a way to just stop whatever event is triggering the drag/drop interaction?

If so, please let me know. I would also like to know if this isn't simple - from Chome Dev Tools it looks like the drag animation is actually handled by workers. But I'm out of my depth here.

If there was mention on how the drag/drop interaction works, or where to find that information, that would be helpful.

Actual behavior

This information is seemingly not easily accessible. Or if it is, I don't know how to find it.

Suggested solution?

Extending the README / docs slightly.

zachsa avatar Apr 07 '20 08:04 zachsa

@zachsa I created a related PR to solve this problem: https://github.com/atlassian/react-beautiful-dnd/pull/1764

Here is the issue: https://github.com/atlassian/react-beautiful-dnd/issues/1722

chuckWu1989 avatar Apr 07 '20 08:04 chuckWu1989

Thanks @chuckWu1989 . Keen to be able to achieve this!

zachsa avatar Apr 07 '20 08:04 zachsa

If I'm understanding correctly, looking forward to this as well!

I have the following structure and want to prevent a drag on Draggables of type A when a Draggable of type B where isDragDisabled is trying to be dragged. The drag handle for DraggableA is the entire element, which houses n number of DraggableBs:

<DragDropContext>
  <Droppable type="A">
    <Draggable>
      <div {...provided.dragHandleProps}>
        <Droppable type="B">
          <Draggable />
          <Draggable isDragDisabled={true} />
          <Draggable />
          <Draggable />
        </Droppable>
      </div>
    </Draggable>
    <Draggable>
      ...
    </Draggable>
    <Draggable>
      ...
    </Draggable>
  </Droppable>
</DragDropContext>

Currently, when trying to drag draggable of type B that has isDragDisabled, draggable of type A starts being dragged.

chinanderm avatar May 15 '20 13:05 chinanderm

Having the same problem. I've tried to stop event propagation in onClick, onMouseDown, onMouseMove, onDrag, onDragCapture, onDragStart, onDragStartCapture, but none of them worked.

kreja avatar Feb 19 '21 09:02 kreja

This is highly wanted in my situation - I need to disable drag-capturing inside a draggable on some of its children elements to make other interaction handling possible.

skang avatar May 26 '21 14:05 skang

I have observe that if I skip referal link to droppable element then all draggable elements have a none draggable state.

<Droppable droppableId="droppable">
  {(provided, snapshot) => (
    <StyledTable
      {...provided.droppableProps}
      ref={draggable ? provided.innerRef : null}
    >
    // ....
    </StyledTable>
  )}
</Droppable>

paveltretyakovru avatar Jul 08 '21 17:07 paveltretyakovru

For anyone still trying to get this to work, I figured out a terribly hacky way to prevent dragging on any child element of a Draggable:

/* provided is the object with provided props from the Draggable */
<div
    data-rbd-drag-handle-context-id={provided.dragHandleProps?.["data-rbd-drag-handle-context-id"]}
    data-rbd-drag-handle-draggable-id="gibberish"
    style={{
        // When you set the data-rbd-drag-handle-context-id, RBD applies cursor: grab, so we need to revert that
        cursor: "auto"
    }}
/>

The way RBD starts a drag (at least I think) is by listening for global mousedown events, then identifying the element that was clicked/dragged. Once it has the element, it searches in its parents for an element with data-rbd-drag-handle-context-id set to the corresponding id. Then, it references that element's data-rbd-drag-handle-draggable-id to figure out what's being dragged. If we set the context-id to the actual value but set the draggable-id to gibberish, RBD will error when you try to drag the div (since it can't find the corresponding Draggable) and abort the entire drag and drop process, which is exactly what we want (minus the error printed in the console, which should only show up in dev mode).

Merlin04 avatar Mar 24 '22 19:03 Merlin04

@zachsa I created a related PR to solve this problem: #1764

Here is the issue: #1722

You two are not talking about the same problem

zhaochengxian avatar Apr 10 '22 05:04 zhaochengxian

For anyone still trying to get this to work, I figured out a terribly hacky way to prevent dragging on any child element of a Draggable:

/* provided is the object with provided props from the Draggable */
<div
    data-rbd-drag-handle-context-id={provided.dragHandleProps?.["data-rbd-drag-handle-context-id"]}
    data-rbd-drag-handle-draggable-id="gibberish"
    style={{
        // When you set the data-rbd-drag-handle-context-id, RBD applies cursor: grab, so we need to revert that
        cursor: "auto"
    }}
/>

The way RBD starts a drag (at least I think) is by listening for global mousedown events, then identifying the element that was clicked/dragged. Once it has the element, it searches in its parents for an element with data-rbd-drag-handle-context-id set to the corresponding id. Then, it references that element's data-rbd-drag-handle-draggable-id to figure out what's being dragged. If we set the context-id to the actual value but set the draggable-id to gibberish, RBD will error when you try to drag the div (since it can't find the corresponding Draggable) and abort the entire drag and drop process, which is exactly what we want (minus the error printed in the console, which should only show up in dev mode).

This worked for me

dexkode4 avatar Jun 28 '22 21:06 dexkode4

@Merlin04 Thanks! That is indeed terribly hacky, but it works so idc and it's also kind of brilliant lol as I'm sure that required some digging to figure out, appreciate you posting your finding !! <3

DevPowers avatar May 10 '23 03:05 DevPowers