jQuery drag and drop - checking for a drop outside a droppable

最后都变了- 提交于 2019-11-28 04:40:21
Luke Girvin

Because the droppable's drop event fires before the draggable's stop event, I think you can set a flag on the element being dragged in the drop event like so:

jQuery('#droppable').droppable(
{
    accept: '#draggable',
    drop: function(event, ui)
    {
        ui.helper.data('dropped', true);
        // awesome code that works and handles successful drops...
    }
});

jQuery('#draggable').draggable(
{
    revert: false,
    start: function(event, ui) {
        ui.helper.data('dropped', false);
    },
    stop: function(event, ui)
    {
        alert('stop: dropped=' + ui.helper.data('dropped'));
        // Check value of ui.helper.data('dropped') and handle accordingly...
    }
});

I see that you already got an answer; anyway I had this same problem today and I solved it this way:

var outside = 0;

// this one control if the draggable is outside the droppable area
$('#droppable').droppable({
    accept      : '.draggable',
    out         : function(){
        outside = 1;
    },
    over        : function(){
        outside = 0;
    }
});

// this one control if the draggable is dropped
$('body').droppable({
    accept      : '.draggable',
    drop        : function(event, ui){
        if(outside == 1){
            alert('Dropped outside!');
        }else{
            alert('Dropped inside!');
        }
    }
});

I needed that because I couldn't change the options of my draggables, so I had to work only with droppables (I needed it inside the awesome FullCalendar plugin). I suppose it could have some issues using the "greedy" option of droppables, but it should work in most cases.

PS: sorry for my bad english.

EDIT: As suggested, I created the version using the jQuery.data; it can be found here : jsfiddle.net/Polmonite/WZma9/

Anyway jQuery.data documentation say:

Note that this method currently does not provide cross-platform support for setting data on XML documents, as Internet Explorer does not allow data to be attached via expando properties.

(meaning that it doesn't work on IE prior to 8)

EDIT 2: As noted by @Darin Peterson , the previous code doesn't work with more than one drop-area; this should fix that issue: http://jsfiddle.net/Polmonite/XJCmM/

EDIT 3: Example from EDIT 2 has a bug. If I drag "Drag me!" to the bottom droppable, then drop "Drag me too" to the upper droppable and then drop "Drag me too" outside, it alerts "Dropped inside!" So, don't use it.

EDIT 4: As noted by @Aleksey Gor, the example in Edit 2 was wrong; actually, it was more of an example to explain how to loop through all the draggables/droppables, but I actually forgot to remove the alert messages, so it was pretty confusing. Here the updated fiddle.

ggzone

Try to use the event "out" of a droppable element.

This is the documentation

"This event is triggered when an accepted draggable is dragged out (within the tolerance of) this droppable." If I'm right, this is what you need.

What is also possible is to create an element overlay over the whole page. If the element is dropped there you fire your event. Not the best, but I think the only way to do it. Because you need some other "droppable" item to fire these events.

The advantage of the following example, is that you don't need to change or know about the droppable code:

The draggable revert property can have a function(value){}. A value is passed as argument, indicating if helper was dropped onto an element (the drop element), or 'false' if not dropped on an element (drop outside or not accepted).

Note: you need to return the correct bool value from that revert-function, in order to tell the helper to revert or not (true/false). True means yes, take the helper back to its original position, by moving it back in a slow motion (out-of-the-box). False means no, just remove the helper abdruptly. Setting the revert property to 'invalid', is a shortcut of saying

  • 'yes, if dropped outside, then revert helper'
  • 'no, if dropped on a droppable element and accepted, then kill the helper right away'.

My guess is that you can add current ui helper to draggable container with data property during start event. Then pick it up in the revert function from the data property. Then add a property to the helper, indicating if it was dropped or not. Then ultimately in the stop event, check this data property value, and do what you intended.

Order of event/function calls for draggable: start-revert-stop

This could be an example:

jQuery('#draggable').draggable(
{
    start: function(event, ui) {
        $(this).data('uihelper', ui.helper);
    },
    revert: function(value){
        var uiHelper = (this).data('uihelper');
        uiHelper.data('dropped', value !== false);
        if(value === false){
             return true;
        }
        return false;
    },
    stop: function(event, ui)
    {
        if(ui.helper.data('dropped') === true){
            // handle accordingly...
        }
    }
});

You can even return true in the revert function, and just remove the helper during the stop event instead, depending on the data('dropped') value with ui.helper.remove(). Or you could even explode it with CSS3 if you still have a bad day ;)

I add the solution I adopted since you can understand this very easily from the css classes of the object you are moving:

jQuery('#draggable').draggable({
  stop: function(event, ui) {
    if (ui.helper.hasClass('ui-draggable-dragging')) {
      console.log('dropped out');
    } else {
      console.log('dropped successfully');
    }
  }
});

Old question and old answers mean that this "may" be a new solution. You (maybe) also wanted, as the question states, to know IF a draggable was dropped outside of a droppable. For me, in at least 95% of the cases, I don't really care IF, I just want things to go back to how they were without any changes being made WHEN that happens.

Setting revert to the string invalid accomplishes the desired behavior without any extra code or funky things to do.

$( '#draggable' ).draggable({
    revert: "invalid",
    stop: function( event, ui )
    {
       // whatever
    }
});

Again, it won't tell you "if it was dropped outside of a droppable," but it will revert to the initial state if that happens.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!