skip to Main Content

I’m attempting to setup drag and drop in my project

I’ve got several fields setup like this
enter image description here
If a user clicks the image on the left and drags, they can re-order the rows

When a valid dropzone is detected (in this case, any other row is a valid dropzone) a class is applied to the div wrapping all elements of that row which renders a border underneath to indicate where the dropped row will be inserted
enter image description here

My problem is, for some reason, if I drag a row over one of the input or select elements that are a child of the dropzone, they are concidered to be the dropzone rather than the underlying element.
enter image description here
Its a little hard to see but theres a dashed line under the right most input indicating my dropzone class has been added.

How its setup

The following JS is called for each valid dropzone

function dropzone(node, options) {
  console.log(`created dropzone on ${node}`);
  let state = {
    dropEffect: "move",
    dragover_class: ["dropzone", "pb-3"],
    ...options,
  };

  function handle_dragenter(e) {
    console.log(`DragEnter ${e.target}`);
    e.stopPropagation();
    e.target.classList.add(...state.dragover_class);
  }

  function handle_dragleave(e) {
    console.log(`DragLeave ${e.target}`);
    e.stopPropagation();
    e.target.classList.remove(...state.dragover_class);
  }

  function handle_dragover(e) {
    console.log(`DragOver ${e.target}`);
    e.stopPropagation();
    e.dataTransfer.dropEffect = state.dropEffect;
  }

  node.addEventListener("dragenter", handle_dragenter, true);
  node.addEventListener("dragleave", handle_dragleave, true);
  node.addEventListener("dragover", handle_dragover, true);
}

What I’ve tried

CSS

I’ve tried adding pointer-events: none; to all children of my dropzone class thats added in my dragenter handler which works but only when the dropzone is successfully entered before any of its children. I’ve also tried blanked setting pointer-events: none; on all child elements of dropzones which does fix the issue but it also prevents the inputs from working

JS

I’ve tried setting useCapture to true when adding my event listeners via addEventListener and calling e.stopPropagation() inside all of my handlers which to my understanding should cause the node the event listener is added to (in this case, the dropzone row) to be called first before propogating down to all children. However, the inputs are still receiving dragenter events

useCapture feels like the most promising approach but I must me missing something here (or it doesnt work on drag events for some reason).

Can anyone see anything obviously wrong with my setup or provide me with any other suggestions to fix my issue?

EDIT: I’ve gotten things working reasonably well by

  1. using this rather than e.target in my handlers. Turns out e.target always references the element the event fired on (i.e. what your mouse if over) where as this or e.currentTarget references the element with the listener attached
  2. Even with the above, I was leave and enter events firing when I moved the mouse between any of the children of a dropzone which caused lots of graphical issues. This was fixed by implementing a basic reference counter so whenever you dragenter fires, the counter is incremented and when dragleave is fired its decremented. The class adding the underline is only removed when this counter reaches 0.

I’m still open to suggestions that can make this better but I’m happy with the current result

2

Answers


  1. Restructuring your HTML would be the ideal way to go but you can also…

    add these events to all children that you don’t want to be drop zones:

    <select ondrop="" ondragover=""></select>
    

    For a quick & dirty fix.

    Login or Signup to reply.
  2. You can restructure the HTML in this way…

    Instead of the drag/drop elements having CHILDREN that bubble, make them their SIBLINGS so they won’t be inheriting the drag/drop.

    The parent will now be a wrapper that holds them all together as siblings and with no more bubbling issues.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search