invertedSpear
invertedSpear

Reputation: 11054

jQueryUI droppable, stop propagation to overlapped sibling

As you can see here: http://jsfiddle.net/rA4CB/6/

When I make the drop in the overlapped area it is received in both droppables, greedy doesn't work when the items are siblings. Is there any way to block the reception on droppables lower in the zIndex?

BTW, mouseOver won't fire for the droppable element as the mouse is actually over the draggable element.

relevant JS:

$(function() {
    $( "#draggable" ).draggable();
    $( "#droppable" ).droppable({
        tolerance:'pointer',
        drop: function( event, ui ) {
            $( this )
                .addClass( "ui-state-highlight" )
                .find( "p" )
                    .html( "Dropped!" );
        }
    });
    $( "#droppable2" ).droppable({
        tolerance:'pointer',
        greedy:true,
        drop: function( event, ui ) {
            $( this )
                .addClass( "ui-state-highlight" )
                .find( "p" )
                    .html( "Dropped!" );
        }
    });
});

Upvotes: 11

Views: 11749

Answers (9)

user3921104
user3921104

Reputation: 164

It's very similar to invertedSpear answer. I had to change it a little bit because enabling/disabling inside "over"/"out" didn't work for me .I had to do below instead

$("#droppable2").droppable({
    greedy: true,
    drop: function (event, ui) {
        $("droppable").droppable("disable");
    }
}

I had to explicitly enable"droppable" div when I needed it. For instance, enable it when starting the drag event. Eg

$("#drageMe").draggable({
 start:function(event,ui){
   $("droppable").droppable("enable");  

} })

Upvotes: 0

invertedSpear
invertedSpear

Reputation: 11054

Okay, so I spend an hour trying to figure it out, then as soon as I ask I then find my answer

http://jsfiddle.net/rA4CB/7/

Modified the JS to the following:

$(function() {
    $( "#draggable" ).draggable();
    $( "#droppable" ).droppable({
        tolerance:'pointer',
        drop: function( event, ui ) {
            $( this )
                .addClass( "ui-state-highlight" )
                .find( "p" )
                    .html( "Dropped!" );
        }
    });
    $( "#droppable2" ).droppable({
        tolerance:'pointer',
        greedy:true,
        drop: function( event, ui ) {
            $( this )
                .addClass( "ui-state-highlight" )
                .find( "p" )
                    .html( "Dropped!" );
        },
        over: function(event, ui){
            $( "#droppable" ).droppable( "disable" )
        },
        out: function(event, ui){
            $( "#droppable" ).droppable( "enable" )
        }
    });
});

Upvotes: 15

Deivydas Pocius
Deivydas Pocius

Reputation: 1

So, when trying to find simple solution I came up with this (and it works for me):

            window.overNowOnThis = "";
            window.olderOnes = [];
            $obj.droppable({
                accept: ".draggable_imgs",
                drop: function(e, ui) {
                    if(window.overNowOnThis == this){
                        // Do whatever
                    }
                },
                over: function(event, ui){
                    window.olderOnes.push(window.overNowOnThis);
                    window.overNowOnThis = this;
                },
                out: function(){
                    var lastElem = window.olderOnes.pop();
                    window.overNowOnThis = lastElem;
                }
            });

Top element would be selected because on it "over" fires the last one. Also - if there is more than two siblings - then when moving out of element we set the last one as current. Using global "window" was for example. Better option would be using classes as it can safely keep data.

Upvotes: 0

dee34
dee34

Reputation: 61

$( "#droppable" ).droppable({
    greedy: true,
    drop: function( event, ui ) {
       if(ui.helper.is(".dropped")) {
           return false;
       }
       ui.helper.addClass(".dropped");
    }
});

Just set a css class on ui.helper of draggable. If the draggable has been accepted once, it will be refused by all other droppables (Could be done with the droppable "accept" parameter,too , like accept : ":not(.dropped)" and the class added to ui.draggable).

Upvotes: 6

Seetpal singh
Seetpal singh

Reputation: 3849

try greedy option in ui dropable. see the fiddle link below for demo:

http://jsfiddle.net/creators_guru/3vT5C/embedded/result/

$( ".circles" ).droppable({
    greedy: true,
    drop: function( event, ui ) {
        $_data  =   ('drgged class = ' + ui.draggable.attr('class'));
        $_data1 =   ('droped id = #' + $(this).attr('id'));
        $('#data').html($_data + '<br/>'+$_data1);
        return false;
    }
});

Upvotes: -1

user3114072
user3114072

Reputation:

In certain circonstances :

myjQuery.droppable({
  over:function(evt,ui){
    ui.draggable.attr('drg_time', this.drg_time = evt.timeStamp)
  },
  accept:function(draggeds){
    if(draggeds.attr('drg_time'))
    {
      return draggeds.attr('drg_time') == this.drg_time
    }
    return draggeds.hasClass('acceptable_classes_here')
  },
  out:function(evt,ui){
    // useless but cleaner
    ui.draggable.removeAttr('drg_time')
  }
  drop:...,
})

Upvotes: 1

Lalit Kumar Maurya
Lalit Kumar Maurya

Reputation: 5565

If you have a number of droppable in a container area then what????

You must re think for that problem. Greedy works for only parent to child relationship not in siblings. So you must edit droppable js or put your own logic for it.

So if you have a numbers of droppable then you must write some extra code to handle dropping on perfect droppable as it is in this example A number of siblings droppables

For making perfect siblings droppable modify your droppbale as below

        var topElement = undefined;
        var topElementArray = Array();

        $( "#draggable" ).draggable();
        $( ".droppableBox" ).droppable({
            activeClass: "active-droppable",
            tolerance:'pointer',
            over: function( event, ui ) { 
                // This is for only show a message that z-index must be required for proppable
                // you can remove it after testing or after development
                if ($(this).css("z-index") == 'auto') {
                    alert("Please provide z-index for every droppable.");
                    return;
                }
                //

                topElement = undefined;
                topElementArray = Array();
                // Change it as you want to write in your code
                // For Container id or for your specific class for droppable or for both
                $('#demo > .droppableBox').each(function(){                     
                    _left = $(this).offset().left, _right = $(this).offset().left + $(this).width();
                    _top = $(this).offset().top, _bottom = $(this).offset().top + $(this).height();
                    if (event.pageX >= _left && event.pageX <= _right && event.pageY >= _top && event.pageY <= _bottom) {   
                          topElementArray.push($(this).attr('id'));
                    }
                });
            },
            drop: function( event, ui ) {
                if (!topElement) {
                    topElement = determineTopElement(topElementArray);
                }                   
                if ($(this).attr('id') == $(topElement).attr('id')) {
                    $( this ).addClass( "ui-state-highlight" ).find( "p" ).html( "Dropped!" );
                  // Your code after successful dropped element on specific siblings
                  // Start writing code for dropped element & perfect droppable
                }

            }
        });

        determineTopElement = function(_array) {
            var topElement;
            var zIndexHighest = 0;
            for (i = 0; i < _array.length; i++){
               var element = $("#"+ _array[i]);
               var z_index = $(element).css("z-index");
               if( z_index > zIndexHighest){
                   zIndexHighest = z_index;
                   topElement = element;
               }
            }
            return topElement;       
        }

Upvotes: 2

Derek Liang
Derek Liang

Reputation: 1222

I find that using #invertedSpear's method will cause UI state change which is not desirable in some cases. Here is the code.

var lastOpertion = new Date().getTime();

drop: function (event, ui) {
        if (new Date().getTime() - lastOpertion < 100) return;
        lastOpertion = new Date().getTime();
        ....
}

Upvotes: 0

klanm
klanm

Reputation: 3258

I had the same problem and made a small plugin :)

check it out:

https://stackoverflow.com/a/16720944/1308461

Upvotes: 0

Related Questions