Recently a reader asked about a tricky issue with HTML5 drag and drop. The issue is this:
HTML5 supports native drag and drop through draggable property and several events such as dragstart, drag, dragenter, dragleave, dragover and drop. Normally dragstart event handler is where you set the data that is to be transferred between the drag source and drop target. The drop event handler is where you handle the drop of a drag source, access the data transferred and process it further. Now, in this particular case he had handled only the dragstart and drop events. And the drop event handler never used to get called. In other words dragging operation was successful but dropping operation was not.
To understand the problem and the solution clearly, let's quickly recreate the problem in a simple web form. Consider the following HTML markup:
<form id="form1" runat="server">
<div id="div1" style="width:300px;height:300px;border:2px solid red" draggable="true"></div>
<div id="div2" style="width:300px;height:300px;border:2px solid red"></div>
</form>
As you can see there are two <div> elements. The first element - div1 - is draggable as indicated by the draggable attribute. The second div - div2 - acts as the drop target.
Now, consider the following jQuery code that handles the dragstart and drop events:
$(document).ready(function () {
var div1 = $("#div1").get(0);
var div2 = $("#div2").get(0);
div1.addEventListener("dragstart", function (e) {
$("#div1").html('drag started...');
e.dataTransfer.setData('text/html', 'hello world');
}, false);
div2.addEventListener("drop", function (e) {
e.stopPropagation();
e.preventDefault();
$("#div2").html(e.dataTransfer.getData('text/html'));
return false;
}, false);
});
The dragstart event handler sets the HTML of div1 to 'drag started...' and sets data to be transferred to 'hello world'. The drop event handler calls stopPropagation() and preventDefault(), and sets the HTML of div2 to the data passed via dataTransfer object. When you drag div1 and drop onto div2, you would expect div2 to display 'hello world'.
Now the tricky thing is that if you run the above code (Chrome or Firefox) it won't fire the drop event at all. The solution is to handle dragover event also. The default handler for dragover doesn't allow drop. This design ensures that something can be dropped only on a developer defined valid target and that all elements don't act as a valid drop targets by default. So, even if you don't want to do anything specific in dragover event handler add one as shown below:
div2.addEventListener("dragover", function (e) {
e.preventDefault();
}, false);
After adding dragover event handler, run the web form and now the drag-n-drop should work as expected.