Search code examples
jqueryjquery-uidraggabledroppable

JQueryUI droppable drop event fires before reverting


I have a revert function so I can add some extra checks that will trigger a revert. The drop function to align the draggable with the droppable seems to fire before the draggable is reverted back to its original position.

It seems to me that this only happens if the revert function is used, as on a disabled droppable it acts normally.

$( ".box" ).draggable({
  revert: function(socketObj) {
    if (socketObj === false) {
      return true;
    } else {
        if ( $(this).hasClass("box") ) {
        return true;
      }
      return false;
    }
  },
});

$( ".ru" ).droppable({
  drop: function( event, ui ) {
    ui.draggable.position({
      of: $(this),
      my: 'left top',
      at: 'left top'
    });
  }
});

https://jsfiddle.net/ugywztgw/


Solution

  • I'd say this is the proper behavior.

    Disabled droppable is just like any other non-drop area. You'll get the same behaviour when you drop the draggable somewhere else in the window.

    Think about the other users that needs to execute some logic on drop, whether it was a valid drop or not. for example a game where user is only given n turns to drop, whether they were valid or not, or similar scenarios. If drop event't doesn't fire at all for non-valid drops, they'll complaint that they need a way to detect drop.

    Think about invoking drop handler after reverting, which is what you're asking -

    That doesn't make sense at all. Drop happened first, the decision whether to revert or not was taken based on the dropped item, after drop. It's not like if you hover a non-valid item over a droppable it'll revert back. Drop needs to happen, and users need a way to identify it happened.

    Id'd say this is not a bug, this is the most logical behavior targeting larger number of users. You'll need to work around for your specific scenario. How to work around depends on your specific use case.


    In this case, you can move the code that decides whether to revert or not to the drop handler, and execute further code based on the result:

    $(".box").draggable({
      revert: function(elm) {
        return !elm || $(this).hasClass('invalid');
      }
    });
    
    $(".ru").droppable({
      drop: function(event, ui) {
        if (ui.draggable.hasClass("box")) {
          return ui.draggable.addClass("invalid");
        }
        ui.draggable.position({
          of: $(this),
          my: 'left top',
          at: 'left top'
        });
      }
    });
    
    $("#ru4").droppable("option", "disabled", true);
    .box {
      background-color: teal;
      width: 200px;
      height: 30px;
      position: absolute;
    }
    .ru {
      width: 300px;
      height: 30px;
      margin-top: 1px;
      background-color: #888;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
    <div id="containment">
      <div id='ru1' class='ru'>
        <div class="box">Drag me</div>
      </div>
      <div id='ru2' class='ru'>Drops then reverts</div>
      <div id='ru4' class='ru'>Disabled - reverts normally</div>
    </div>