How can I drag and drop elements with HTML/CSS?

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>

Upvotes: 0

Views: 1715

Answers (1)

Corentin
Corentin

Reputation: 21

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

Upvotes: 1

Related Questions