0

I'm trying to trigger a drop-zone for files in my UI but only when you drag a file onto the window a la Google Images. However, the dragenter and dragleave seem to trigger on all children and not just the item I've added the listener to. I've tried preventDefault and stopPropagation but neither helps.

I'm trying to avoid running a parent check on every event trigger since I need it to turn off when you leave the window as well and I'm not sure if it'll work with that since technically the leave still has a parent of inside the window?

My simplified code is as follows:

const [dragging, setDragging] = useState(false);

const dragEnter = event => {
  event.preventDefault();
  event.stopPropagation();
  setDragging(true);
};

const dragLeave = event => {
  event.preventDefault();
  event.stopPropagation();
  setDragging(false);
};

useEffect(() => {
  window.addEventListener("dragenter", dragEnter, false);
  window.addEventListener("dragleave", dragLeave, false);
  return () => {
    window.removeEventListener("dragenter", dragEnter, false);
    window.removeEventListener("dragleave", dragLeave, false);
  };
}, []);

Here's a really simplified demo of it "working". I feel like this has got to be a solved problem but I'm not having a lot of luck Googling it.

This is all going to live inside a React project, though I don't think that's what's getting me here.

dougoftheabaci
  • 665
  • 1
  • 6
  • 19
  • Check out the useCapture option in [addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener). In capture mode (which happens first) the event starts on the body tag and works its way down to the lowest element. Once that has happened and it's reached the element, it will turn around and bubble back up to the body tag. And you can `stopPropagation` from a capturing event, and it will prevent it from going any further. – David784 Jun 05 '20 at 17:39
  • I tried switching it from `false` to `true` and but it still sets and unsets when I drag it over child elements. – dougoftheabaci Jun 07 '20 at 21:20

2 Answers2

1

Ah, I forgot what a pain drag and drop is to work with. The problem isn't bubbling, it's that new events are being triggered like crazy. However fortunately there is a way to fix it credit here. In your case you'd add the following CSS:

.App * {pointer-events: none;}

Here's a modification of your fiddle CSS is being added via style jsx

David784
  • 7,031
  • 2
  • 22
  • 29
  • Yeah, I didn't reach for that because I assumed it would disable the ability to drop on a target. I guess that's not the case? – dougoftheabaci Jun 09 '20 at 17:12
  • If you only want to permit dropping on a particular child, yes, you would have to change that child to `pointer-events: auto`, and then you could potentially get events when crossing that particular element border. AFAIK there's no way around that. If that becomes a problem I'd suggest using the "counter" approach in the next answer up on the question I credited above...at that point it would be about properly managing multiple events rather than preventing them. – David784 Jun 09 '20 at 19:25
0

Use event.currentTarget and check it is the parent element

marcant0
  • 189
  • 8
  • `event.currentTarget` doesn't seem to help here. It always comes back as being the element it was called on initially and every 'leave' is a child of that element. – dougoftheabaci Jun 07 '20 at 21:22