Search code examples
jquery-uijquery-ui-draggablejquery-ui-droppable

jQuery Droppable: Only allow element to drop, if there is no other element in that dropzone


I'm writing a puzzle, where you have to drag an item into the correct dropzone.

Problem: I want that you can only drag an item into a dropzone, if that dropzone does not contain any other items. How can I check, whether there are no other items in that dropzone?

Here is a gif of my current puzzle: enter image description here

Here is a gif which shows the problem:

enter image description here

As you can see, I can drag multiple items into the same dropzone.

If a dropzone already contains an item, the user should not be able to drop another item into that dropzone. How do I achieve that?

My script so far:

        $( ".draggable" ).draggable({ revert: 'invalid', snap: ".dropfield", snapTolerance: 30, snapMode: "inner"});

        $( ".dropfield" ).droppable({
            accept: ".dropling",
            drop: function( event, ui ) {

              if(some-condition){ // if correct word got dragged into the correct dropzone
                  var id = ui.draggable.attr('id');
                  $("#" + id).draggable( 'disable' );
                  $(this).droppable( 'disable' );
                  $("#" + id).css( "background-color", "#7FFF00");
            }
        });

Html-excerpt:

<div id="liebe" class="dropling draggable text-center">
  Liebe
</div>

   <span class="dropfield" value="scheitern">

    </span>

PS: There are already several topics on Stack-Overflow with the same question. However, I'm not intelligent enough to apply the suggested answers to my case. Please help me.

Edit1

Here is a gif which shows my preferred behavior:

enter image description here

I dragged a wrong word into a dropzone. But as long that dropzone is occupied by a word, no other words should be able to be dropped into that dropzone.

My current code:

            if(some-condition){ //correct word


                $("#" + id).draggable( 'disable' );
                $(this).droppable( 'disable' );
                $("#" + id).css( "background-color", "#7FFF00");

                }
            } else { //wrong word
                console.log("wrong word dropped");
                $(this).droppable( 'disable' );
            }

As soon as I drag the wrong word out of the dropzone, the dropzone should become enabled again. But how can I achieve that?


Solution

  • I would advise breaking this into their own functions. This way you can enable and disable drop repeatedly. Not sure what you want to trigger the item to become draggable and droppable again based on the example you have supplied. Based on what you have supplied, I can offer this the following example.

    $(function() {
      function enableDrop($target) {
        console.log("Enabled Drop");
        $target.droppable({
          accept: ".dropling",
          classes: {
            "ui-droppable-hover": "drop-target"
          },
          drop: function(event, ui) {
            var $that = $(this),
              dragWord = ui.draggable.text().trim(),
              $item = ui.draggable;
            if (checkWord(dragWord)) {
              console.log("Accepted: " + $item.attr("id"));
              $item.
              removeClass("draggable")
                .draggable('disable')
                .attr("style", "")
                .appendTo($that);
              disableDrop($that);
              $that.css("background-color", "#7FFF00");
            } else {
              return false;
            }
          }
        });
      }
    
      function disableDrop($target) {
        console.log("Disabling Drop on " + $target.attr("class"));
        $target.droppable("destroy");
      }
    
      function checkWord(w) {
        var result = false;
        console.log("Checked Word: " + w);
        if (w == "Liebe") {
          result = true;
        }
        return result;
      }
    
      $(".draggable").draggable({
        revert: 'valid',
        snap: ".dropfield",
        snapTolerance: 30,
        snapMode: "inner"
      });
    
      enableDrop($(".dropfield"));
    });
    p .dropfield {
      border: 1px solid #ccc;
      border-radius: 3px;
      display: inline-block;
      width: 4em;
      height: 1.5em;
      margin-bottom: -.25em
    }
    
    p .drop-target {
      border: 1px dashed #ccc;
      background-color: #ccc;
    }
    
    .text-center {
      text-align: center;
    }
    
    .draggable {
      border: 1px solid #ccc;
      border-radius: 3px;
      display: inline-block;
      width: 4em;
      height: 1em;
      padding: .25em 0;
      margin-bottom: -.25em
    }
    <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    
    <p>Diese Schlussfolgerung ist <span class="dropfield" value="scheitern"></span>: Ee kann doch nicht sein, dass es gut ist, </p>
    
    <div id="liebe" class="dropling draggable text-center">Liebe</div>
    <div id="absurd" class="dropling draggable text-center">absurd</div>