0

I'm trying to make a drag and drop API to use in my website.

The drag part is working, but when I drop the element on the target div, that div only disappears.

HTML

https://codeshare.io/5Dx4XW

CSS

https://codeshare.io/aVxw89

Java Script

https://codeshare.io/GqZWOA

const draggables = document.querySelectorAll('.draggable');
const dropables = document.querySelectorAll('.dropable');

//Event Listeners

draggables.forEach(draggable =>{
    draggable.addEventListener('dragstart', dragStart)
    draggable.addEventListener('dragend', dragEnd)
})

dropables.forEach(dropable=>{
    dropable.addEventListener('dragenter', dragEnter);
    dropable.addEventListener('dragover', dragOver);
    dropable.addEventListener('dragleave', dragLeave);
    dropable.addEventListener('drop', dragDrop);
})

//Funções

function dragStart(){
    this.className +=' hold';
    setTimeout(() => (this.className = 'desabilitado'), 0);
    this.parentElement.className = 'dropable';
    let clone = this.lastChild.cloneNode(true);
    this.parentElement.appendChild(clone)
}

function dragEnd(){
    this.className = 'draggable'
    this.parentElement.className = ' ';
    this.parentElement.lastChild.remove();
}

function dragOver(e) {
    e.preventDefault();

  }
  
  function dragEnter(e) {
    e.preventDefault();
    this.className += ' hovered';
  }
  
  function dragLeave() {
    this.className = 'dropable';
  }
  
  function dragDrop() {
    this.className = ' ';
    const holded = document.querySelector('.hold');
    this.appendChild(holded);

  }
  
.dragdroparea{
  display: flex;
  flex-direction: row;
  position: relative;
  align-items: center;
  justify-content: center;
  z-index: 50;

  height: 60vh;
  width:  80vw;
}

.coluna{
  display: flex;
  flex-direction: column;
  overflow-y: scroll;
  width: 37vw;
  height: 56vh;
}

.linha{
  display: flex;
  flex-direction: row;
  margin-bottom: 1vw;
}

.draggable{
  position: relative;
  width: 3vw;
  height: 2vw;
  border-radius: 7px;
  background-color: #e25f07;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  margin-right: 0.5vw;
  cursor: move;
  z-index: 10000;
}

.dropable{
  position: relative;
  width: 3vw;
  height: 2vw;
  border-radius: 7px;
  border-color: #e25f07;
  border-style: dashed;
  border-width: 2.3px;
  background-color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  margin-right: 0.5vw;
  z-index: 500;
  color: #e25f07;
  
}

.resposta{
  margin-right: 1vw;
}

.textodrag{
  width: 31vw; 
}

::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
::-webkit-scrollbar-button {
  width: 0px;
  height: 0px;
}
::-webkit-scrollbar-thumb {
  background: #e25f07;
  border: 0px none #ffffff;
  border-radius: 38px;
}
::-webkit-scrollbar-thumb:hover {
  background: #f58d47;
}
::-webkit-scrollbar-thumb:active {
  background: #e25f07;
}
::-webkit-scrollbar-track {
  background: #ebe8e6;
  border: 0px none #ffffff;
  border-radius: 55px;
}
::-webkit-scrollbar-track:hover {
  background: #e8e6df;
}
::-webkit-scrollbar-track:active {
  background: #e8e6df;
}
::-webkit-scrollbar-corner {
  background: transparent;
}

.invisible{
  display: none;
}

.hovered{
  width: 3.5vw;
  height: 2.5vw;
}

.hold {
  border: solid 5px #ccc;
}

.desabilitado{
  display: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
    <link rel="stylesheet" href="./teste2.css">
  
</head>
<body>
    <div class="slide active">      

        <div class="conteudovertical">
            
                <p class="header1" style="line-height: 20%;">Garantias e direitos dos participantes de pesquisa</p><br>
                <p class="rodape1">Agora, arraste todos os direitos dos participantes na caixa ao lado.</p>
            

            <div class="dragdroparea">
                <div class="coluna resposta">
                    <div class="linha">
                        <div>
                            <div draggable="true" class="draggable"><p>1</p></div>
                        </div>
                        <div class="textodrag">
                            <p>Receber as informações do estudo de forma
                                claras</p>
                        </div>    
                    </div>
                    <div class="linha">
                        <div>
                            <div draggable="true" class="draggable"><p>2</p></div>
                        </div>
                        <div class="textodrag">
                            <p>Ter oportunidade de esclarecer dúvidas</p>
                        </div>    
                    </div>
                </div>
                <div class="coluna">
                    <div class="linha">
                        <div class="dropable"></div>
                        <div class="textodrag">
                        <p>A linguagem utilizada tanto na redação do
                            TCLE quanto no processo de consentimento deve
                            ser adequada a população do estudo.</p>
                        </div>
                    </div>
                    <div class="linha">
                        <div class="dropable"></div>
                        <div class="textodrag">
                        <p>Durante o processo de consentimento, e a
                            qualquer momento, o participante deve poder
                            esclarecer quaisquer dúvidas relativas ao estudo e
                            ao seu tratamento.</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
      

        <script src="./scripts/dragAndDrop.js"></script>

</body>
</html>
Alexander Nied
  • 12,804
  • 4
  • 25
  • 45
  • Welcome to SO! As a new visitor, I would recommend reviewing [ask]. A few quick pointers: it is generally preferred to include your code in the question body rather than linked to some outside source. Also, try to express that code as an [mcve] as much as possible. Welcome to the site, good luck, and happy coding! – Alexander Nied Jun 23 '20 at 05:04

1 Answers1

1

It seems that the problem comes from the fact that you are adding the hold class to "this", but cloning a child of this node. So, when the timeout's callback execute at the next cycle, you're basically changing the class of the only element that has the hold class. Then when you try to find that element via querySelector, it can't find it.

If instead of adding that class to "this", you add it to the clone for example: clone.className += " hold";, just after you clone it, then your dragdrop function will be able to find it appropriately and move it to the right place. I guess you probably want to clone the whole element instead of the last child though, or NOT change the class of the '.dropable' element when dropping into it, as the style is going to be off (I guess you'll figure what you want to do exactly from there).

Edit: I was playing with it a little on a personal sandbox, and sometimes the dragEnd event is being fired immediatly. I found this other thread where someone explains that it's because you're modifying the DOM in dragStart, and instead you should do it in dragEnter: https://stackoverflow.com/a/19663227/2998036

Corentin
  • 21
  • 1
  • 3
  • i've remade the js and i achieved this https://codeshare.io/2WB9QE but it still have some problems like I wanted it to be possible to return the item that was dragged to its original location https://i.imgur.com/H0CPXMh.gif – João Victor Antunes Figueira Jun 23 '20 at 06:39
  • You can do that, but you'll have to change a couple of things. First, your initial "1" and "2" will have to have the "dropable" class (along with something to check what you can drop into it, see below). You basically want to do the same behavior that you're doing for the dropable zones on the right, except that they will be a bit different: 1) You cannot drop into them until they are empty 2) You can only drop back the same number that they were initially. For the first point, you could add a similar droppable class (note that you will have to add the event handler after). – Corentin Jun 24 '20 at 04:06
  • For the second point, you could hide the number when dragged out (instead of removing it), then if you're dragging an element into it, check that it is the same number - if it is, then you complete the drop, if not, you cancel it. You could also think about the problem in a different way and handle that logic when you construct the event handlers, by creating all that logic somewhere and referencing to it depending on which element you receive. – Corentin Jun 24 '20 at 04:07
  • On a side note, instead of creating a new anonymous function for each event handler, you should probably use the event passed into your handler: `item.addEventListener("dragend", function(event) { const element = event.target ... }` you could also use a nice ES6 arrow function: `item.addEventListener("dragend", (event) => { const element = event.target ... }`. It would also be helpful to change the naming a bit (`list_items` -> `draggableItems`) (`lists` -> `droppableItems`) so that it's easier to understand what's going on. – Corentin Jun 24 '20 at 04:07