Search code examples
javascriptdrag-and-dropthisarrow-functions

Drag API Function Not Working With Javascript Arrow Functions


I've done my best to find this question already being asking but came up empty handed so I hope this isn't a duplicate.

In short, I've written a factory function to help me with some drag & drop functionality in a project I'm working on, but am seeing different behavior depending on how I write some of the methods inside of it.

Here's the code in total:

  const draggables = document.querySelectorAll(draggablesSelectors);
  const containers = document.querySelectorAll(containersSelectors);

  draggables.forEach(draggableEl => {
    draggableEl.addEventListener("dragstart", dragStart, false);
    draggableEl.addEventListener("dragend", dragEnd, false);
  });

  function dragStart() {
    console.log("drag start");
  }

  function dragEnd() {
    console.log("drag end");
  }

  const returnDraggables = () => {
    return draggables;
  }

  const returnContainers = () => {
    return containers;
  }

  return {returnDraggables, returnContainers};
}

const draggableEls = Draggable(".ship", ".gameboard");

I know using arrow functions changes the lexical scope of this, but what I could use some help understanding is why I'll see "drag start" and "drag end" in the console when I write the dragStart and dragEnd functions the way they are above, but when I write them as arrow functions they don't do anything.

Thanks very much!

UPDATE: Thanks to @kikon for helping me realize I had the function declarations after the forEach loop. Once I moved things into the correct order (shown below) everything is working great.

  const draggables = document.querySelectorAll(draggablesSelectors);
  const containers = document.querySelectorAll(containersSelectors);

  // Draggables Functions
  const dragStart = () => {
    console.log("drag start");
  }

  const dragEnd = () => {
    console.log("drag end");
  }

  const dragDrop = () => {
    console.log("drop");
  }

  // Container Functions
  const dragOver = () => {
    console.log("drag over");
  }

  const dragEnter = () => {
    console.log("drag enter");
  }

  const dragLeave = () => {
    console.log("drag leave");
  }

  const returnDraggables = () => {
    return draggables;
  }

  const returnContainers = () => {
    return containers;
  }

  draggables.forEach(draggableEl => {
    draggableEl.addEventListener("dragstart", dragStart, false);
    draggableEl.addEventListener("dragend", dragEnd, false);
    draggableEl.addEventListener("drop", dragDrop, false);
  });

  containers.forEach(containerEl => {
    containerEl.addEventListener("dragover", dragOver, false);
    containerEl.addEventListener("dragenter", dragEnter, false);
    containerEl.addEventListener("dragleave", dragLeave, false);
  });

  return {returnDraggables, returnContainers};
}

const draggableEls = Draggable(".ship", ".gameboard");
console.log(draggableEls.returnDraggables());
export default Draggable;```

Solution

  • I think the cause might be the fact that you declare/define the handlers dragStart and dragEnd after they are used in the forEach loop.

    That works with functions, as they are hoisted, but not with vars or consts. Still, if you used const, as for the other arrow functions, you should have got a ReferenceError.