Drag and drop, have all the elements on one side or the other

1

I have the following code, it is a simple drag and drop. It happens that when I move the elements of div1 to div2 I can move all the elements, but when I try to move the elements of div2 to div1 I can only move one at a time. The question is how to modify it so that this last happens.

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

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

function drop(ev) {drag1
  ev.preventDefault();
  var data = ev.dataTransfer.getData("text");
  ev.target.appendChild(document.getElementById(data));
}
#div1, #div2 {
    float: left;
    width: 200px;
    height: 200px;
    margin: 10px;
    padding: 10px;
    border: 1px solid black;
    }
<h2>Drag and Drop</h2>
<p>Drag the image back and forth between the two div elements.</p>

<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
  <input type="text" draggable="true" ondragstart="drag(event)" id="drag1"> 
  <input type="text" draggable="true" ondragstart="drag(event)" id="drag1"> 
  <input type="text" draggable="true" ondragstart="drag(event)" id="drag1"> 
</div>



<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
    
asked by Kinafune 30.07.2018 в 15:36
source

2 answers

3

Abounding in TheVicious response: when you do appendChild(elemento) and the item you selected using id that is repeated, you are trying to add a child you already have, identified by that id.

In other words, if all draggable divs have the same id drag1 the node identified by document.getElementById('drag1') is always the first node of the document with that id . In this case, the first node #drag1 within #div1 and, if it does not have children, then the first node #drag1 within #div2 . In practice, if you put your children's content, you'll see that dragging the second one actually drags the first one :

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

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

function drop(ev) {drag1
  ev.preventDefault();
  var data = ev.dataTransfer.getData("text");
  ev.target.appendChild(document.getElementById(data));
}
#div1, #div2 {
    float: left;
    width: 200px;
    height: 200px;
    margin: 10px;
    padding: 10px;
    border: 1px solid black;
    }
<h2>Drag and Drop</h2>
<p>Drag the image back and forth between the two div elements.</p>

<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
  <input type="text" draggable="true" ondragstart="drag(event)" id="drag1" value="soy el primero"> 
  <input type="text" draggable="true" ondragstart="drag(event)" id="drag1" value="soy el segundo"> 
  <input type="text" draggable="true" ondragstart="drag(event)" id="drag1" value="soy el tercero"> 
</div>



<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>

Then:

  • You move a node from #div1 to #div2 , this is the first node #drag1 child of #div1 and you can move it.
  • The node identified by #drag1 now the first child of #div1 , which originally was in the second place. The item you moved went to third place.
  • Already at this point you can not move anything back, because what is in the #div2 when trying to select it returns a reference to the first child of #div1 .

  • After the 3 children are moved from #div1 to #div2 , there is no longer any node #drag1 in #div1 therefore the first node #drag1 is the first child node of #div2 . You can move any of those children to #div1 but you will be moving the first one.

  • When you move one of those back, again the selector #drag1 is a reference to the first child of #div1 ignoring what is inside #div2 .
  • One solution is to give a unique id to each input you want to move, but you could actually do the same without using ids for the draggables. It would be a matter of storing a reference to the moving element in a global variable element .

    With this you could have infinite draggable nodes and not have to worry about giving them a unique id:

    var element=null;
    
    function allowDrop(ev) {
      ev.preventDefault();
    }
    
    function drag(ev) {
      element=ev.target;
    }
    
    function drop(ev) {
      ev.preventDefault();
      ev.target.appendChild(element);
      element=null;
    }
    #div1, #div2 {
        float: left;
        width: 200px;
        height: 200px;
        margin: 10px;
        padding: 10px;
        border: 1px solid black;
        }
    <h2>Drag and Drop</h2>
    <p>Drag the image back and forth between the two div elements.</p>
    
    <div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
      <input type="text" draggable="true" ondragstart="drag(event)" value="soy el primero" > 
      <input type="text" draggable="true" ondragstart="drag(event)" value="soy el segundo" > 
      <input type="text" draggable="true" ondragstart="drag(event)" value="soy el tercero"> 
    </div>
    
    
    
    <div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>

    Final suggestion

    Let's add some style to the subject so that it looks nice, and also let's make sure that only the elements #div1 and #div2 can receive children . Otherwise, you can drag one input into another and it will disappear.

    var element = null;
    
    function allowDrop(ev) {
      ev.target.classList.add('feedme');
      ev.preventDefault();
    }
    
    function removeDrop(ev) {
      ev.target.classList.remove('feedme');
      ev.preventDefault();
    }
    
    function drag(ev) {
      element = ev.target;
      element.parentNode.classList.add('feedme');
      element.classList.add('dragging');
    }
    
    function drop(ev) {
      ev.preventDefault();
      ev.target.classList.remove('feedme');
      element.classList.remove('dragging');
      if (ev.target.classList.contains('droppable')) {
        ev.target.appendChild(element);
      }
      element = null;
    }
    #div1,
    #div2 {
      float: left;
      width: 200px;
      height: 200px;
      margin: 10px;
      padding: 10px;
      border: 1px solid black;
    }
    
    #div1 input,
    #div2 input {
      cursor: ew-resize;
    }
    
    #div1.feedme,
    #div2.feedme {
      background: #FFFFEE;
    }
    
    .dragging {
      border: 1px dashed #00F;
      cursor: move;
    }
    <h2>Drag and Drop</h2>
    <p>Drag the image back and forth between the two div elements.</p>
    
    <div id="div1" class="droppable" ondrop="drop(event)" ondragover="allowDrop(event)" ondragleave="removeDrop(event)">
      <input type="text" draggable="true" ondragstart="drag(event)" value="soy el primero">
      <input type="text" draggable="true" ondragstart="drag(event)" value="soy el segundo">
      <input type="text" draggable="true" ondragstart="drag(event)" value="soy el tercero">
    </div>
    
    
    
    <div id="div2" class="droppable" ondrop="drop(event)" ondragover="allowDrop(event)" ondragleave="removeDrop(event)"></div>
        
    answered by 30.07.2018 / 16:20
    source
    4

    This is why you are placing the same id for all input id="drag1" , to solve it modify your id

    function allowDrop(ev) {
      ev.preventDefault();
    }
    
    function drag(ev) {
      ev.dataTransfer.setData("text", ev.target.id);
    }
    
    function drop(ev) {drag1
      ev.preventDefault();
      var data = ev.dataTransfer.getData("text");
      ev.target.appendChild(document.getElementById(data));
    }
    #div1, #div2 {
        float: left;
        width: 200px;
        height: 200px;
        margin: 10px;
        padding: 10px;
        border: 1px solid black;
        }
    <h2>Drag and Drop</h2>
    <p>Drag the image back and forth between the two div elements.</p>
    
    <div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
      <input type="text" draggable="true" ondragstart="drag(event)" id="drag1"> 
      <input type="text" draggable="true" ondragstart="drag(event)" id="drag2"> 
      <input type="text" draggable="true" ondragstart="drag(event)" id="drag3"> 
    </div>
    
    
    
    <div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
        
    answered by 30.07.2018 в 15:54