Tuesday, June 12, 2018

Prevent drop event when it's already have child element ? Drag and Drop

Leave a Comment

I am doing the simple matching game. The game has multiple question. I am using drag and drop for matching. First of all, I'll drop the image element to one container, when I select another element and try to drop it into the same container, currently it's overwriting the existing element. I want to check the container, which already has the element. If it doesn't have, allow that to drop, otherwise prevent the drop.

Code:

<!DOCTYPE HTML> <html> <head> </head> <meta name="viewport" content="width=device-width, initial-scale=1">     <!-- Bootstrap -->     <link href="manage/css/bootstrap.min.css" rel="stylesheet">     <!-- Custom Styles -->     <link href="css/style.css" rel="stylesheet">     <script src="manage/js/jquery-2.1.4.min.js"></script>     <style> .left, .right {     float: left;     width: 100px;     height: 35px;     margin: 10px;     border: 1px solid black; } </style> </head> <body> <h2>Matching the following</h2> <div class = "container-fluid">      <div class="row">         <div class = "col-md-2">             Option A         </div>         <div class = "col-md-1">                 <div class="left" id="left_1">                     <img src="manage/images/login.png" draggable="true" ondragstart="drag(event)" id="drag1" width="88" height="31">                 </div>         </div>         <div class = "col-md-4">         </div>         <div class = "col-md-1">                 <div  id="right_1" class="right" ondrop="drop(event)" ondragover="allowDrop(event)">                 </div>         </div>         <div class = "col-md-2">         Option B Matching          </div>     </div>      <div class="row">         <div class = "col-md-2">             Option B         </div>         <div class = "col-md-1">                 <div class="left" id="left_2">                     <img src="manage/images/login.png" draggable="true" ondragstart="drag(event)" id="drag2" width="88" height="31">                 </div>         </div>         <div class = "col-md-4">          </div>         <div class = "col-md-1">                 <div class="right" id="right_2" ondrop="drop(event)" ondragover="allowDrop(event)">                 </div>         </div>         <div class = "col-md-2">         Option A Matching         </div>     </div> </div>  <script>  function allowDrop(event) {     event.preventDefault(); }  function drag(event) {     event.dataTransfer.setData("text", event.target.id); }  function drop(event) {     event.preventDefault();     var rightId = event.target.id;     console.log("before"+($("#"+rightId).children().length));     if($("#"+rightId).children().length == 0){         console.log($("#"+rightId).children().length);         var data = event.dataTransfer.getData("text");         event.target.appendChild(document.getElementById(data));     }     console.log("after"+($("#"+rightId).children().length)); } </script></body></html> 

Screen Shot

For Reference

I want to prevent the drop event, when container already has child elements. In the same time I need to rearrange the dropped elements, when any one container empty for swapping.

Actually i want to drag the image from left container to right container. before dropping the element to right container, i want to check if container already have another image which dropped before. if there is no image in container, allow to drop the image, or else prevent dropping the image.

Awaiting suggestions. Thanks in advance!

2 Answers

Answers 1

I think that can you check collision between elements and take decision you actions

follow the example link to see if there is a collision using vanilla javascript and jquery:

Vanilla JS Div Collision Detection

How to detect div collision in my case?

https://jsfiddle.net/jeanwfsantos/bp57zgrL/

<style> #div1 {   width: 100px;   height: 100px;   border: 1px solid #aaaaaa;   padding: 10px; }  .element {   width: 100px;   height: 100px; } </style> <div    id="div1"    ondrop="drop(event)"    ondragover="allowDrop(event)"></div> <div      class="element"      id="drag1"      style="background: blue;"      draggable="true"      ondragstart="drag(event)"      ondrag="dragMove(event)"></div> <div      class="element"      id="drag2"      style="background: red;"      draggable="true"      ondragstart="drag(event)"      ondrag="dragMove(event)"></div>  <script> const elements = document.querySelectorAll('.element') let hasCollision = false let offset = [0, 0]  function allowDrop(ev) {   ev.preventDefault() }  function drag(ev) {   ev.dataTransfer.setData('text', ev.target.id)   offset = [     ev.target.offsetLeft - ev.clientX,     ev.target.offsetTop - ev.clientY   ] }  function drop(ev) {   ev.preventDefault()   const data = ev.dataTransfer.getData('text')   if (!hasCollision) {     ev.target.appendChild(document.getElementById(data))   } }  function dragMove(e) {   hasCollision = Array.prototype.some.call(elements, d => {     if (d.id !== e.target.id) {       return isCollide(e, d)     }     return false   }) }  function isCollide(a, b) {   const aRect = a.target.getBoundingClientRect()   const bRect = b.getBoundingClientRect()   return !(     ((a.clientY + offset[1] + aRect.height) < (bRect.top)) ||     (a.clientY + offset[1] > (bRect.top + bRect.height)) ||     ((a.clientX + offset[0] + aRect.width) < bRect.left) ||     (a.clientX + offset[0] > (bRect.left + bRect.width))   ) } </script> 

I hope this helps you.

Answers 2

I think your real problem is that you've implemented allowDrop(event) as event.preventDefault() so a drop is always permitted.

Instead what you want to do is disallow a drop in a case where the target is already occupied. Try using the following implementation of allowDrop():

function allowDrop(event) {     var t = event.target;     // Find the drop target     while (t !== null && !t.classList.contains("target")) {         t = t.parentNode;     }     // If the target is empty allow the drop.     if (t && t.childNodes.length == 0) {         event.preventDefault();     }     return false; } 

Here's a fiddle that shows it in action. (I freely acknowledge I borrowed based on the previous answer. :)

let offset = [0, 0]    function allowDrop(ev) {    var t = ev.target;    while (t !== null && !t.classList.contains("target")) {      t = t.parentNode;    }    if (t && t.childNodes.length > 0) {      return false;    }    ev.preventDefault()  }    function drag(ev) {    ev.dataTransfer.setData('dragID', ev.target.id)    offset = [      ev.target.offsetLeft - ev.clientX,      ev.target.offsetTop - ev.clientY    ]  }    function drop(ev) {    ev.preventDefault()    const data = ev.dataTransfer.getData('dragID')    ev.target.appendChild(document.getElementById(data))  }
.target {    width: 100px;    height: 100px;    border: 1px solid #aaaaaa;    padding: 10px;  }    .element {    width: 100px;    height: 100px;  }
<div class="target" ondrop="drop(event)" ondragover="allowDrop(event)"></div>  <div class="element" id="drag1" style="background: blue;" draggable="true" ondragstart="drag(event)"></div>  <div class="element" id="drag2" style="background: red;" draggable="true" ondragstart="drag(event)"></div>

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment