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

Droppable triggers OUT event after DROP


I have a batch of small stones, which are draggable and can be dropped in some groups. For proper highlighting I use the OVER and OUT event. But I have some troubles with the DROP and OUT event. As I drag and drop a stone in the group the OVER and DROP events are triggered, but as soon as I pick up the next stone (move it just enough that I'm over the threshold for dragging) the 'old' OUT event is trigged.

Has anyone experienced same problems and could help me out?

My droppable, the group, is stetted up like this:

   $('.group').droppable({
        accept: this.canItBeDropped.bind(this),
        drop: this.drop.bind(this),
        over: this.over.bind(this),
        out: this.out.bind(this),
    });

And my draggables, the stones, like this:

    this.$stone.draggable({
        distance: 3,
        revert: 'invalid',
        revertDuration: 400,
        scroll: false,
        stack: '.stone',
        refreshPositions: true, 
    });

EDIT

After some further digging into the library, I found out that it has something to do with my custom accept function. But the library calls it with the new stone, not with the old one what I would have expected.


Solution

  • I finally fixed the problem and will describe it, just in case anyone will have a similar problem in the future.

    The trouble was caused because as soon as I dropped a stone my custom accept function would return false because now this stone wouldn't fit in the group as it is already in it (a requirement for my project)

    So my fix was to just determine the result for the if statement before the actual dropping

        drop: function( draggable, event ) {
    
            var dropped = false;
    
            // Create a copy of the droppables in case the list changes during the drop (#9116)
            $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
    
                if ( !this.options ) {
                    return;
                }
    
                // determine the result for the if statement beofre the dropping
                let deactivate = !this.options.disabled && this.visible 
                    && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) 
    
                if ( !this.options.disabled && this.visible && 
                        intersect( draggable, this, this.options.tolerance, event ) ) {
                    dropped = this._drop.call( this, event ) || dropped;
                }
    
                if (deactivate) {
                    this.isout = true;
                    this.isover = false;
                    this._deactivate.call( this, event );
                }
    
            } );
            return dropped;
    
        }