3

I am having an issue with drag and drop.

My issue is that when one element is dropped into the dropzone it will sometimes be inserted into another element and not the dropzone div.

jsFiddle: http://jsfiddle.net/kMbPF/

In the example you can see I have made the tables very large so that it would be very easy to see this. When one table is dropped on top of another table, it does not go into the drop zone with the other elements, but gets inserted inside of another table.

I had a couple of ideas, but I have no idea if they would work. One was if somehow a large div could be inserted over the dropzones to ensure that the elements are always dropped into it. I would see this as almost a transparent layer that catches the elements then places them in the drop zone.

My other idea was to try and get all of the data from the div, put it all into a string, and try to parse this and then replace all the data back into the dropzone.

Also as you will notice, sorting works but only seems to in Firefox, not Safari. This is not my most pressing concern, but if you did happen to see a fix that would be great!(sorting only works on the upper dropzone) I do not want to use jQuery.

Code:

<!DOCTYPE html>

<html lang="en">
<head>
    <title>Basic drag and drop example</title>

    <style>
    @CHARSET "UTF-8";
table.draggable-word {
    background-color: red;
    padding: 0px;
    border: 1px solid green;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    border-collapse: collapse;
    border-spacing: 0;
    padding: 0;
    margin: 0;
    line-height: 1;
    width: 100%;
    height:50px;
}

.drop-div {
    width: 150px;
    height: 150px;
    border: 3px solid #224163;
    background-color: #AABACC;
    margin-top: 15px;
    text-align: center;
    overflow: auto;
}

[draggable=true] {
    cursor: default;
    margin-top: 0px;
    margin-bottom: 0px;
    margin-top: 0px;
}

table {
     border-color: #600;
    border-width: 0 0 1px 1px;
    border-style: solid;
}
    </style>


    <script>

var user ="";
var multiples = false;
var data;

function dragStartHandler(event,id) {
    event.dataTransfer.setData('Object', event.target.id);
    user = id;
    multiples = true;
     data = event.dataTransfer.getData('Object');
    //multipleDrag(data,"false");

}
function dropHandler(event) {
    preventDefaults(event);
    if (!event.target) {
        alert('we');
        event.target = event.srcElement
    }
    data = event.dataTransfer.getData('Object');
    event.target.appendChild(document.getElementById(data));
    document.getElementById(data).selectedIndex = -1;
    //alert(user);



}
function dragOverHandler(event) {
    preventDefaults(event);
}

function preventDefaults(event) {
    if (event.preventDefault) {
        event.preventDefault();
    }

    try {
        event.returnValue = false;
    }
    catch (exception) {}
}


function dragend(event) {
//    multipleDrag(data,"true");

}

function multipleDrag(data,state){
    document.getElementById(data).setAttribute("draggable", state);
}

function sort(uList)
{
    var listItem = document.getElementById(uList).getElementsByTagName('td');
    var listLength = listItem.length;
    var list = [];

    for(var i=0; i<listItem.length; i++){
        list[i] = listItem[i].id.substring(1,listItem[i].id.length);         
        list.sort(function(a,b) {return parseInt(a) > parseInt(b)})
    }
    for(var i=0; i<listLength; i++){
        listItem[i].firstChild.nodeValue = list[i];
    }



}   

        </script>

</head>

<body>



<div class="drop-div"
     ondragover="dragOverHandler(event);"
     ondrop="dropHandler(event)"
     id="drop-div1" ondragend="sort('drop-div1')"></div>

     <div class="drop-div"
     ondragover="dragOverHandler(event);"
     ondrop="dropHandler(event)"
     id="drop-div2">
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'3');"
     class="draggable-word"id="d3" ondragend="dragend(event);"
     ><tr><td id="d3">3</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d4" ondragend="dragend(event);"><tr><td id="d4">4</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d5" ondragend="dragend(event);"><tr><td id="d5">5</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d6" ondragend="dragend(event);"><tr><td id="d6">6</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d7" ondragend="dragend(event);"><tr><td id="d7" >7</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d8" ondragend="dragend(event);"><tr><td id="d8" >8</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d9" ondragend="dragend(event);"><tr><td id="d9">9</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d10" ondragend="dragend(event);"><tr><td id="d10">10</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d11" ondragend="dragend(event);"><tr><td id="d11">11</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d12" ondragend="dragend(event);"><tr><td id="d12">12</td></tr></table>
     <table  draggable="true"
     ondragstart="dragStartHandler(event,'4');"
     class="draggable-word"
     id="d13" ondragend="dragend(event);"><tr><td id="d13">13</td></tr></table>
</div>
 <div id="print"></div>
</body>
</html>​
Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
dannyn382
  • 363
  • 2
  • 5
  • 15

1 Answers1

5

The drop event is being fired on child elements, so your event.target is the child element. This is normal event bubbling and is only to be expected.

Instead of immediately appending to the event.target like this:

event.target.appendChild(document.getElementById(data));

You need to first find the parent dropzone element. This is quite straightforward if you have something like jQuery you can simply use the closest method. If you don't, then something like this will work (untested, you'll probably need to iron out some bugs):

var dropzone = event.target;
while (dropzone.id != 'drop-div1') {
    dropzone = dropzone.parentNode;
}
dropzone.appendChild(document.getElementById(data));
Community
  • 1
  • 1
robertc
  • 74,533
  • 18
  • 193
  • 177
  • Exactly what I was looking for. Thank you! I updated the file. http://jsfiddle.net/kMbPF/15/ The issue I am having now is that the 'drop-div1' is hard coded into the while loop, so this works perfect when going from the lower div to the upper div. I cannot get it to work backwards. Do you know how to dynamically get the div id of the dropzone that the element in is going in? I was thinking something along the lines of scanning the ids like http://tinyurl.com/95lmu3r and then having all the div id that are drop zones start with a certain naming convention? I am a little lost on how to. – dannyn382 Oct 24 '12 at 03:10
  • 1
    I seem to have gotten it. http://jsfiddle.net/kMbPF/16/ I used substring. Two questions, would you be able to point me in the correct direction for a way to hold down shift to select multiple elements, and also a way to make sure that the text can never be highlighted and only one element can move at a time, unless shift has been used to select multiple elements. I am basically trying to create a selection box, and tried using a selection box, but it turns out some browsers do not allow options in a selection box to be made draggable! Thanks again for your help! – dannyn382 Oct 24 '12 at 05:48
  • Also, I cannot seem to figure out why I cannot get the javascript to work in Safari for the sorting. Works perfectly in FireFox, but does not work in Safari. Here is the most recent file. http://jsfiddle.net/kMbPF/17/ Thanks! – dannyn382 Oct 24 '12 at 06:39
  • @dannyn382 If you have multiple elements which can be dropped on then use a `class` and scan the `className` attribute in the loop. If you have more questions, ask more questions, don't put them in comments here where only I am likely to see them. – robertc Oct 24 '12 at 07:47
  • Thank you again. I see what you are saying, effectively that is what I did with substring, except mine was very crude. Your way is much more polished. I did not want to ask another question seeing the button said answer your question, so I thought that meant that it would mark the question answered. Thanks! – dannyn382 Oct 24 '12 at 14:50
  • @dannyn382 There's a big button at the top right of the page which says 'Ask a question' – robertc Oct 24 '12 at 16:10