Skip to content
Advertisement

HTML Drag & drop api not working when dropping elements (React)

I have a web page where words need to be rearranged by drag and drop method. The app is built with React. My issue is that when the element is dropped in the drop zone/area, the id that was set by the target element is blank. This was the original error TypeError: Failed to execute ‘appendChild’ on ‘Node’: parameter 1 is not of type ‘Node’. I tried console logging the id text during drop and it shows up blank.

const handleDragStart = (e:DragEvent<HTMLHeadingElement>) => {
    
    e.dataTransfer.dropEffect = "move";
    e.dataTransfer.setData("elementID", e.target.id);
}

const handleDragDrop = (e:DragEvent<HTMLDivElement>) => {
    
    const data = e.dataTransfer.getData("elementID");
    console.log(data) //prints nothing
    e.target.appendChild(document.getElementById(data));
}

const handleDragOver = (e:DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
}

return(
<>
   <div className="display-flex">
        {["before", "calm", "storm", "the"].map((elem, i)=>(
            <h4 key={elem} id={`draggable-${i}`} draggable="true" onDrag={handleDragStart} className="px-1 b-1 m-1">{elem}</h4>
        ))}
   </div>
   <div className="b-1 p-1 h-2" onDrop={handleDragDrop} onDragOver={handleDragOver}>
            <p>Drop Zone</p>
   </div>
</>
)

Advertisement

Answer

You should use the onDragStart instead of the onDrag on the draggable element:

You can read more here

import React from "react";

const Com = () => {
  const drag = (e) => {
    e.dataTransfer.setData("id", e.target.id);
    e.dataTransfer.dropEffect = "move";
  };
  const handleDragDrop = (e) => {
    e.preventDefault();
    const data = e.dataTransfer.getData("id");
    const el = document.getElementById(data);
    el && e.target.appendChild(document.getElementById(data));
  };

  const handleDragOver = (e) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
  };

  return (
    <>
      <div className="display-flex">
        {["123"].map((elem, i) => (
          <h4
            key={elem}
            id={`draggable-${elem}`}
            draggable="true"
            onDragStart={drag}
            className="px-1 b-1 m-1"
          >
            {elem}
          </h4>
        ))}
      </div>
      <div
        className="b-1 p-1 h-2"
        onDrop={handleDragDrop}
        onDragOver={handleDragOver}
      >
        <p>Drop Zone</p>
      </div>
    </>
  );
};
export default Com;

See it running here on CodeSandbox

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement