Adam Rackis
Adam Rackis

Reputation: 83366

Drag dataTransfer data unavailable in ondragover event

I'm trying to get the hang of html5 drag and drop events.

function rowDragStart(event) {
    let targetRowId = event.target.attributes.row.value;
    event.dataTransfer.setData("text/plain", targetRowId);
}

function rowDragOver(event) {
    event.preventDefault();
    let draggingId = event.dataTransfer.getData('text');
}

For now I'm just trying to put something in the dataTransfer object in dragStart, and retrieve it in dragOver. The problem is it's not present in drag over. I've set breakpoints and these events are getting called, but getData('text') returns empty string, along with every other possibility I can think of.

Upvotes: 24

Views: 9048

Answers (2)

WheretheresaWill
WheretheresaWill

Reputation: 6500

As a follow-on to another answer that points out that:

the dragover event is Protected mode so the data transfer types are available but the data itself is unavailable.

There is a slightly hacky workaround for transferring small amounts of string data by adding it into the type name itself e.g.

function dragstart_handler(ev) {
  const someDataToTransfer = "something-like-an-id";
  ev.dataTransfer.setData(`hackymethod-${someDataToTransfer}`, null);
}

function dragover_handler(ev) {
  const dataType = ev.dataTransfer.types.find((type) => type.startsWith("hackymethod-"));
  const yourData = dataType.replace("hackymethod-", "");
  ev.preventDefault();
}

Upvotes: 0

Dekel
Dekel

Reputation: 62666

According to the Event-Summary of the HTML5 Drag&Drop specification, the mode of the Drag data store's dragover event is Protected mode.

Protected mode:

The formats and kinds in the drag data store list of items representing dragged data can be enumerated, but the data itself is unavailable and no new data can be added.

This is for both files and html5 element's drag&drop.

In other words - you can access the types of the dragged elements and the number of elements dragged, but their data is not available until you do the actual drop.

This is by design

Here is an example for the HTML5 elements drag&drop:

function dragstart_handler(ev) {
  console.log("drag start");
  // Change the source element's background color to signify drag has started
  ev.currentTarget.style.border = "dashed";
  // Set the drag's format and data. Use the event target's id for the data 
  ev.dataTransfer.setData("text/plain", ev.target.id);
}

function dragover_handler(ev) {
  console.log("drag over, total types:", ev.dataTransfer.types.length, 'type available:', ev.dataTransfer.types[0]);
  ev.preventDefault();
}

function drop_handler(ev) {
  console.log("drop, total types:", ev.dataTransfer.types.length, 'data dropped:', ev.dataTransfer.getData('text/plain'));
  ev.preventDefault();
  
  // Clear the drag data cache (for all formats/types)
  ev.dataTransfer.clearData();
}
div {
  margin: 0em;
  padding: 2em;
}
#source {
  color: blue;
  border: 1px solid black;
}
#target {
  border: 1px solid black;
}
<div>
  <p id="source" ondragstart="dragstart_handler(event);" draggable="true">
    Select this element, drag it to the Drop Zone and then release the selection to move the element.</p>
</div>
<div id="target" ondrop="drop_handler(event);" ondragover="dragover_handler(event);">Drop Zone</div>

Upvotes: 42

Related Questions