views:

989

answers:

2

I have two droppable divs that are very close to each other on the screen (note: they are not nested). A large draggable div is dragged on top of the two divs; when the mouse is released, the draggable happens to fall on both droppable divs (i.e. two droppable events are fired).

What I would like to happen, is that in this scenario, the draggable will fall on only one droppable and nother other. Order does not matter at all.

What is the best way in doing this?

One inefficient way that came to my mind is keep track of all droppable event timestamps, and reject a droppable event if it has a timestamp that was already stored before in some array.

A: 

You could use the 'data' method on the droppable elements to store a reference to the draggables they've accepted so far. So, for instance, you can do something like this:

<script language="javascript">
$(function() {
    $('.droppable').droppable({
        greedy:true,
        [...other:options],
        over: function(event,ui) {
            var already_dragged = $(this).data('mysite.dropped_items');
            if($.inArray(ui.draggable.id,already_dragged) >= 0) {
                $(this).droppable('disable');
            }
        },
  out: function(event,ui) {
   $(this).droppable('enable');
  },
  drop: function(event,ui) {
   var already_dragged = $(this).data('mysite.dropped_items');
            if($.inArray(ui.draggable.id,already_dragged) < 0) {
    already_dragged.push(ui.draggable.id);
                $(this).data('mysite.dropped_items',already_dragged);
            }
  }
    }).data('mysite.dropped_items',new Array());
});
</script>

<div id="droppable1" class="droppable"></div>
<div id="droppable2" class="droppable"></div>
<div id="draggable_1" class="draggable"></div>

Essentially what this is doing is this...

We've used the jQuery data object to attach an array called 'mysite.dropped_items' to each $('.droppable') element. Every time you hover a draggable over one of these droppables, the system will check to see if that droppable's id is already in its 'mysite.dropped_items' array. If it is, then the droppable will become disabled. If it's not, everything will work as expected.

I haven't tested this exact block of code but in theory, it should work. I hope that helps.

KyleFarris
the logic is sound. only thing though is that the draggable that I have does not have a unique ID; mainly because the same draggable is used over and over again.so without a unique id, what should i store as key to identify a draggable that has been dropped before
Hady
A: 

I was able to solve my problem in a slightly different way. Let me first recap what my situation is again:

  1. I have two droppable div objects that are very close to each other on the screen
  2. I have a draggable div, that does not have a unique ID. This draggable can be dropped on my droppables time and time again (i.e. it doesn't get consumed, if that makes any sense)
  3. When a draggable is on top of two droppables, currently the jquery behaviour is that the draggable will hit both droppables. This is an undesired effect for me.
  4. My expected behaviour: the draggable should fall on the first droppable only, and should not get triggered for any other subsequent droppable which is around.

    var tsArray = new Array();

    $('.droppable').droppable({ drop : function() {

    for (var i = 0; i < tsArray.length; i++) {
        if (tsArray[i] + 150 > ev.timeStamp) {
            return;
        } 
    }
    
    
    tsArray.length = 0; // Empty it for performance
    tsArray.push(ev.timeStamp);
    
    
    // Do any logic you require here
    

    });

The basic idea is that when a draggable is dropped on two droppables, the event timeStamp of each droppable event are very close to each other. They are milliseconds apart. I simply do a check to ensure that there is a substantial time difference between them.

Hady
On a slow enough computer, or a computer hiccuping for some reason, this may not work. In some instances, it could very well take up to a full second for the draggable to be accepted. Consider dynamically attaching a unique identifier to each draggable. It's worth the 5 extra minutes you'll spend.
KyleFarris
That won't work Kyle. Lets assume my draggable is '#boo'. When the draggable is dropped on TWO droppables, both of them will be receiving an event of a draggable that has the unique idenitifier '#boo'. I need only one draggable to be dropped at a time, even if it is above more than one droppable.
Hady