Search code examples
jqueryjquery-ui-droppable

When using jquery-ui Droppable, why does the accept event fire right when someone starts dragging a draggable?


I have a page with a large number of jquery UI draggables and a large number of droppables. I wanted some custom logic to determine if a droppable would accept a certain draggable so i coded up some logic in the "accept" event of the droppable. It worked but one thing i noticed is that this event fires right when you start dragging an item and it fires for all droppables at that time.

That seems very inefficient. I was thinking it would right for a single droppable right when you hover but that doesn't seem to be the case. Is there any reason why you think its coded this way (as it seems very inefficent as if i have 100 droppables, its firing 100 times even if if the user only tries to drag into a single droppable) and also, is there any way to have the behavior that i want .

I thought of putting logic into the drop event to simple do my check and delete the draggable item (to simulate not accepting it) but the issue there is that you don't get any of that nice "revert' animation so it looks a bit inconsistent (compared the what you would see if you based on the accept event)

Any thoughts on how I can still plug in some custom logic but not waste the cycles to fire on every single droppable right when i move something (and still get the revert animation) ?


Solution

  • I don't think the overhead is that great, but if you do want an alternative solution: Grab the start position of the draggable element on start and save it in data() of the element. In the drop routine do the logic check. If it failed, animate the element back to the startPosition. This will ensure the events are specific to only the element being dragged and the droppable.

    http://jsfiddle.net/samnunnally/sgy29/2/

    <!doctype html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <title>droppable demo</title>
    <link rel="stylesheet"
        href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
    <style>
    
    #notAllowed {
        width: 100px;
        height: 100px;
        background: #ccc;
    }
    
    #allowed {
        width: 100px;
        height: 100px;
        background: red;
    }
    
    #droppable {
        position: absolute;
        left: 250px;
        top: 0;
        width: 125px;
        height: 125px;
        background: #999;
        color: #fff;
        padding: 10px;
    }
    </style>
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
    </head>
    <body>
        <div id="droppable" >Drop here</div>
        <div id="notAllowed" >not allowed to drop</div>
        <div id="allowed">allowed to drop</div>
        <script>
    
            function capturePosition(event, ui) {
    
                ui.helper.data( 'startPosition', ui.position);
            }
    $( document ).ready(function() {
    
            $("#notAllowed").draggable({
                start : capturePosition
            });
    
            $("#allowed").draggable({
                start : capturePosition
            });
    
            $("#droppable").droppable({
                drop : function(event, ui) {
                    //do logic to determine if it can be dropped
                    if(ui.draggable.attr('id') == 'notAllowed'){
                       var startPosition = ui.draggable.data('startPosition');
                       ui.draggable
                        .animate({ 
                        'left': 
                        '+='+ (startPosition.left - ui.draggable.offset().left + $('body').offset().left) + 'px' }, 
                        'slow' )
    
                        .animate({
                        'top': 
                        '+='+ (startPosition.top - ui.draggable.offset().top + + $('body').offset().top) + 'px' }, 
                        'slow' );
                    }
                }
            });
    }
        </script>
    </body>
    </html>