Shopify / draggable

The JavaScript Drag & Drop library your grandparents warned you about.
https://shopify.github.io/draggable
MIT License
17.93k stars 1.09k forks source link

Prevent dragging on child interactive element #183

Open a-korzun opened 6 years ago

a-korzun commented 6 years ago

Hi there! Does Draggable support to prevent drag event on any interactive child element? Example: I have a list with items that contains checkbox, it is so hard to check input w/o drag element.

Live Preview: https://codepen.io/akorzun/pen/aYwXoR

Gif: mar-23-2018 15-20-57

beefchimi commented 6 years ago

You could do something clever on drag:start that looks at the mouse position and compares it against the position of the button, and cancel if its overtop of that button. Perhaps that would work.

@tsov what do you think about introducing a class like .draggable-cancel or .draggable-prevent-default, and if a drag is initiated when the touch or mouse or whatever is overtop that element, the drag never happens? That way, users can have child links / buttons that can be clicked while still being within a draggable item.

a-korzun commented 6 years ago

@beefchimi ok, thank. I have a solution https://codepen.io/akorzun/pen/aYwXoR

Hope this idea is not so terrible to implement into this project.

tsov commented 6 years ago

@katasup One way to get around the issue is to increase the default drag delay:

new Draggable(containers, {
  // ...
  delay: 300,
  // ...
})

that way there is enough time to check/uncheck checkboxes or even click links/buttons, but also allow to start dragging when holding the mouse down longer.

@beefchimi We could create a plugin that automatically prevents dragging when the target is an input field or even contenteditable, what do you think?

beefchimi commented 6 years ago

@tsov I feel like thats a good start... but we should offer something more flexible.

Let's say I have a div instead of a button because "reasons". And I want a click on that div to trigger some action unrelated to dragging. I feel like I should have an easy way to tell draggable "ignore dragging if I'm clicking on this child element".

My expectation is to:

Then Draggable will know to cancel when attempting to drag an item where that "undraggable child element" is the target.

jhull commented 6 years ago

What is the status of this?

I'm running into a similar issue - pop-up modal with textareas, child element of draggable div. When user tries to select text 'draggable' class is added to the modal and a ghost-image of it floats behind the modal.

Would love to be able to disable draggable on child elements...

ncovercash commented 6 years ago

I think I've "tried" to overcome this issue before by giving a handle using :not, however, I'm not sure if that actually works

tsov commented 6 years ago

@narrative1st interesting, could you elaborate a little more? I want to understand the problem a little more to give a better solution to your problem. A codepen or code example of sorts would be best.

The proposed solution in this issue, can be done manually too (without building out that plugin)

jhull commented 6 years ago

I solved it by moving the child elements into a portal and rendering them outside the draggable component with vue-portal. In the simplest of terms, when you highlight a text selection on a modal above the draggable element, drag thinks you want to drag the elements underneath.

Moving the modal outside of the draggable section fixed the problem for me.

fdietze commented 6 years ago

To disable dragging of a component, I dynamically remove the draggable class. This works well for me.

chunhei37 commented 6 years ago

I solved this problem with mouseover and mouseout events. So, when the user hover on input, select, button, it will update a boolean variable. Then, you can do a check with the boolean.

sudara commented 6 years ago

@beefchimi I'd love to see a plugin that prevents the drag if it's a click coming from a child! A class seems like a really nice declarative way to do that. Right now i'm going to implement something similar to @katasup's solution

AidPuska commented 8 months ago

For people who could have this problem later, I solved it with adding handle on Sortable object, with this handle you can add like button and be able to move that item only on that element by targeting him with class

const sortable = new Sortable(document.querySelectorAll("ul"), {
      draggable: "li",
      handle: ".handle-drag"
    })