5

I have a jQuery UI droppable element which I would like to get bigger when a draggable is hovered over it. I have tried both using the hoverClass option and also binding to the drophover event.

Visually, both these methods work fine. However, once the draggable exits the original (smaller) boundary of the droppable, jQuery UI interprets this as a 'dropout', despite still being within the current (larger) boundary.

For example, js:

$("#dropable").droppable({
    hoverClass: 'hovering'
}.bind('dropout', function () {console.log('dropout')});

css:

#droppable { background: teal; height: 10px; }
#droppable.hovering { height: 200px; }

In this case, when a draggable hovers over the droppable, the droppable visually increases in size to 200px. If at this point, the draggable is moved down by 20px, I would expect it to still be hovering over the droppable. Instead, jQuery UI fires the dropout event and the droppable reverts to being 10px high.

Anyone know how to get it to behave in the way I'd expect it to?

jsFiddle example: http://jsfiddle.net/kWFb9/

lucas
  • 1,910
  • 2
  • 21
  • 25
  • As I couldn't find an answer to this question, I've switched to using the native Drag and Drop API, which doesn't have this problem (though it does have its own list of problems). – lucas Nov 25 '11 at 12:58

4 Answers4

5

Had the same problem, I was able to solve it by using the following options:

$("#droppable").droppable({
    hoverClass: 'hovering',
    tolerance: 'pointer'
});

$('#draggable').draggable({
    refreshPositions: true
});

Here's the working fiddle: http://jsfiddle.net/kWFb9/51/

See http://bugs.jqueryui.com/ticket/2970

rvignacio
  • 1,710
  • 1
  • 18
  • 33
  • The refreshPositions was exactly what I needed...I'm using the AngularJS drag-n-drop from http://codef0rmer.github.io/angular-dragdrop and had an issue where onOver wasn't firing as I was hiding an element prior(animation) – Brian Putt Feb 05 '15 at 22:36
  • Good work rvignacio. This should be marked as the answer:refreshPositions: true – jon Dec 16 '15 at 18:57
  • Thanks for refreshPositions. It worked after 1 hour! – supersan Dec 11 '21 at 07:21
2

So I made a couple tweaks to your fiddle

First I set the droppable tolerance to "touch" which will activate whenever any part of the draggable is touching it. This causes the hovering class to be applied.

Next I added an animation to resize your draggable element slightly. I wasn't sure if this was functionality you wanted or not so I put it in there anyways.

Lastly, I permanently apply the hovering class to the droppable element when the draggable element is dropped into the droppable zone. This way the droppable doesn't revert to that narrow height when there is an element in it

http://jsfiddle.net/kWFb9/2/

EDIT:

Better fiddle: http://jsfiddle.net/kWFb9/6/

I hope this helps :)

Keith.Abramo
  • 6,952
  • 2
  • 32
  • 46
  • This hasn't solved the problem. The droppable still reverts to the narrow height when the draggable is hovering over the bottom part of it. You'll see the problem if you try to drag the draggable so that its bottom is inline with the bottom of the droppable. – lucas Nov 28 '11 at 22:44
  • @lucas I see what you mean. I've edited my answer with a more solid solution – Keith.Abramo Nov 28 '11 at 23:16
1

you could create a bigger (i.e. the size of #droppable.hovering) div without background and apply your droppable to it. Note that you didn't provide HTML but the new #drop_container should contain both divs.

JS

var dropped;
$("#droppable").droppable({
    drop: function(event, ui) {
        dropped = true;
    }
});

$('#draggable').draggable({
    start: function(event, ui) {
        $("#droppable").addClass("hovering");
        dropped = false;
    },
    stop: function(event, ui) {
        if (!dropped) {
            $("#droppable").removeClass("hovering");
        }
    }
});

CSS

#droppable { background: teal; height: 10px; }
#droppable.hovering, #drop_container { height: 200px; }

Or you could try another solution with .live() or .livequery() from this article

[EDIT] I've edited my code and here is a jsfiddle: http://jsfiddle.net/94Qyc/1/

I had to use a global var, I didn't find a better way to check wether the box was dropped. If anybody has an idea, that would be great.

JMax
  • 26,109
  • 12
  • 69
  • 88
  • but then it'd be possible to drop the draggable onto the bottom part of #drop_container without ever interacting with #droppable which would be confusing for the user. – lucas Oct 24 '11 at 13:36
  • @lucas: I've edited my answer to use `activate` and `deactivate`. Please post a jsfiddle or at least your HTML so that we could try if it still doesn't fit your needs. – JMax Oct 24 '11 at 14:32
  • In this solution, the droppable gets bigger when the drag starts. I'm looking to make it bigger on **hover**. – lucas Oct 25 '11 at 14:13
0

There is an other (hum hum) not bad solution :

TL;DR: Fiddle

The problem is that the plugin stores dom element's size values when the widget is created (something like) :

//jquery.ui.dropable.js
$.widget("ui.droppable", {
   ...
    _create: function() {

    var proportions,
       this.proportions = function() { return proportions; }

And the offset for widgets are initialized in $.ui.ddmanager.prepareOffsets(); So we only need to overwrite the proportions object.

This way allow to access to real plugin properties so we can write something like :

$("#droppable").droppable({
    hoverClass: 'hovering',
    over: function(ev, ui) {
        var $widget = $(this).data('droppable');
        $widget.proportions = {
            width: $(this).width(),
            height: $(this).height()
        };    
    },
    out: function(ev, ui) {
        var $widget = $(this).data('droppable'); //ui-droppable for latests versions
        $widget.proportions = {
            width: $(this).width(),
            height: $(this).height()
        };
    }
})
DEY
  • 1,770
  • 2
  • 16
  • 14