javascripthtmlcssdragula

How can I limit the number of elements going to drop-area using dragula?


I have such a drag-and-drop problem. I've used the library of dragula. I want to limit the number of elements going to the drop-area to two. Like this:

Here is my code:

  function $(id) {
  return document.getElementById(id);
}

dragula([$('draggable'), $('drop-area')], {
  revertOnSpill: true
});
#chart, #chart tr {
    border: solid 3px;
    width: 1000px;
    border-collapse: collapse;
    font-family: "Almarai";
    font-size: 20px;
}
#chart {
    position: relative;
    left: 200px;
}
#chart #drop-area {
    height: 100px;
}
.gu-mirror {
  position: fixed !important;
  margin: 0 !important;
  z-index: 9999 !important;
  padding: 1em;
}
.gu-hide {
  display: none !important;
}
.gu-unselectable {
  user-select: none !important;
}
.gu-transit {
  opacity: 0;
}
.gu-mirror {
  opacity: 1;
}
<script src="https://rawgit.com/bevacqua/dragula/master/dist/dragula.js"></script>
<table id="chart">
<tr>
<td id="drop-area">
</td>
</tr>
</table><br>
<div id="draggable">
<div id="a1">option 1</div>
<div id="a2">option 2</div>
<div id="a3">option 3</div>
<div id="a4">option 4</div>
<div id="text"></div>

Please help! Thank you in advance.


Solution

  • There are a variety of ways you can approach this based on the various events available in the dragula api.

    You can use the on('drop', callback) event and check the length of children and use cancel().

    I've also used the on('over') event to change class on drop zone and on('cancel') to remove it.

    There are lots of available events you can play with to make the UI more intuitive as needed

    function $(id) {
      return document.getElementById(id);
    }
    
    const dropContainer = $('drop-area');
    
    const drake = dragula([$('draggable'), dropContainer], {
      revertOnSpill: true
    });
    
    drake.on('drop', function(el, target, source, sibling) {
      if (target.matches('#drop-area') && target.children.length > 2) {
        drake.cancel()
      }
    });
    
    drake.on('cancel', function(el, container, source) {
      console.log('Cancelled')
      dropContainer.classList.remove('invalid')
    
    })
    
    drake.on('over', function(el, container, source) {
      if (container !== source && container.matches('#drop-area')) {
        // moved from source to dropzone
        if (container.children.length === 2) {
          container.classList.add('invalid')
        }
      }
    })
    #chart,
    #chart tr {
      border: solid 3px;
      width: 1000px;
      border-collapse: collapse;
      font-family: "Almarai";
      font-size: 20px;
    }
    
    #drop-area.invalid {
      background: yellow;
      color: red
    }
    
    #chart {
      position: relative;
      left: 200px;
    }
    
    #chart #drop-area {
      height: 100px;
    }
    
    .gu-mirror {
      position: fixed !important;
      margin: 0 !important;
      z-index: 9999 !important;
      padding: 1em;
    }
    
    .gu-hide {
      display: none !important;
    }
    
    .gu-unselectable {
      user-select: none !important;
    }
    
    .gu-transit {
      opacity: 0;
    }
    
    .gu-mirror {
      opacity: 1;
    }
    <script src="https://rawgit.com/bevacqua/dragula/master/dist/dragula.js"></script>
    <table id="chart">
      <tr>
        <td id="drop-area">
        </td>
      </tr>
    </table><br>
    <div id="draggable">
      <div id="a1">option 1</div>
      <div id="a2">option 2</div>
      <div id="a3">option 3</div>
      <div id="a4">option 4</div>
      <div id="text"></div>