I know there are plenty of questions and answers ab out this topic but I could not find one with my exact problem.
Due to COVID19, I am not allowed not share and use physical cards with my students, so I tried to implement an HTML5 app as an alternative.
I have a grid with multiple divs (each one with a image resembling each card) and the students must take one at a time and drag and drop it into another div, so the dropped cards must be overlaying one another. The images would have transparent backgrounds so if they select the appropriate cards they would obtain the correct image with all the stacked cards.
I have managed to drag and drop individual cards from its original div to the target and back to its original div, but when I dropped more than one card in the same div, the latter dropped card disappears.
I do not know if the fuse or what happens, but although in this code snippet the images are the same, the images I use do not show fused (remember they have transparent backgrounds and it could be easily seen if I am moving two cards together, glued).
I am not a developer, so I would appreciate a pure JS solution since this way I think I could control and understand better what I am doing.
How can I fix this issue?
The next step would involve the use of socket.io so all can play together (so anyone can see in his/her PO which cards other students have moved) and not each one in their own. But I will leave this questions until I solve this problem.
Thank you.
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));
//~ ev.target.style.backgroundImage = document.getElementById(data);
}
#drag1, #drag2, #drag3, #drag4{
width: 100%;
height: 100%;
}
#div1{
float: left;
width: 25px;
height: 25px;
border: 1px solid black;
}
#div2 {
float: left;
width: 50px;
height: 50px;
border: 1px solid black;
}
.grid-container {
display: grid;
grid-template-columns: auto auto auto auto auto auto auto auto;
grid-template-rows: auto auto auto auto auto ;
}
*[draggable=true] {
-moz-user-select:none;
-khtml-user-drag: element;
cursor: move;
}
.row {
display: flex;
}
<div class="grid-container">
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)" >
<img src="https://www.w3schools.com/images/w3schools_green.jpg" draggable="true" ondragstart="drag(event)" id="drag1" >
</div>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" draggable="true" ondragstart="drag(event)" id="drag2" >
</div>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" draggable="true" ondragstart="drag(event)" id="drag3" >
</div>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" draggable="true" ondragstart="drag(event)" id="drag4" >
</div>
<div>
<div id ="div2" class="grid-item" ondrop="drop(event)" ondragover="allowDrop(event)"> </div>
</div>
As @sol pointed me in the right direction, finally I managed to solve the issue just changing slightly the drop event as follows:
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
var parent = ev.target.parentNode;
parent.appendChild(document.getElementById(data));
}
I make sure that the target is always the same, so although the div contains multiple images, the drop target will always be their parentNode, therefore the div, the container. However, this requires that the div as from the beginning a child, I used and image as template for the cards. Otherwise, the drop event will look for the div's parent and not for the div itself (the child parent). I hope I have explained it properly.