Search code examples
javascripthtmldrag-and-drop

Child elements are allowing drag/drop


I'm having a weird issue with dragging and dropping in html5.

Panel A has a list of the type of elements you can drag. Panel B is where the elements are dragged. Panel C and D are other places you can drag elements, and you can drag and rearrange elements between Panels B, C and D.

My issue is that I'm able to drag an element and drop it INSIDE of another element that's inside one of the panels, which I don't want the user to be able to do. The child elements of those panels don't have any kind of javascript or drag-related properties attached to them, and yet they are currently allowing elements to be dragged inside them.

I've tried attaching "ondrop='return false;'" and "ondragover='return false;'", but neither has worked.

Surely there is a way to turn off the 'allow dragging into' property on an element?

Here's my code:

<div id="elem-002" draggable="true" ondragstart="drag(event)">content</div>

The main panel:

<div id="panel-b" ondrop="drop(event)" ondragover="allowDrop(event)">
  <div id="elem-001" draggable="true" ondragstart="drag(event)">content</div>
</div>

The JS:

function allowDrop(ev) {
    ev.preventDefault();
}

function drag(ev) {
    ev.dataTransfer.setData("Text", ev.target.id);
}

function drop(ev) {
    ev.preventDefault();
    var data = ev.dataTransfer.getData("Text");
    ev.target.appendChild(document.getElementById(data));
}

Said another way: I'm able to drag my "elem-002" directly into "elem-001", an element that was already dragged in. This causing nesting of elements that I don't want to occur. How can I prevent this?


Solution

  • Basically you have to set the correct ev.dataTransfer.dropEffect in allowDrop. For your draggable elements it should be "none" (dropping is not allowed), and for everything else (or any other element where dropping is allowed) to "all"

    Further reading of dropEffect

    Live example:

    window.allowDrop = function(ev) {
        ev.preventDefault();
        if (ev.target.getAttribute("draggable") == "true")
            ev.dataTransfer.dropEffect = "none"; // dropping is not allowed
        else
            ev.dataTransfer.dropEffect = "all"; // drop it like it's hot
    };
    
    window.drag = function(ev) {
        ev.dataTransfer.setData("id", ev.target.id);
    };
    
    window.drop = function(ev) {
        ev.preventDefault();
        var id = ev.dataTransfer.getData("id");
    
        var dragged = document.getElementById(id);
        ev.target.appendChild(dragged);
        dragged.className += " dropped";
    };
    .drag {
        display: inline-block;
        padding: 5px;
        background: rgba(0, 0, 0, 0.2);
        margin: 2px;
    }
    
    .dropzone {
        background: #ccc;
        padding: 5px;
        margin-top: 10px;
    }
    <div id="first" class="drag" draggable="true" ondragstart="drag(event)">1</div>
    <div id="second" class="drag" draggable="true" ondragstart="drag(event)">2</div>
    
    <div class="dropzone" ondrop="drop(event)" ondragover="allowDrop(event)"><div id="third" class="drag dropped" draggable="true" ondragstart="drag(event)">3</div></div>