Reputation: 6412
Firstly, I know this question has been asked before, both in this site and others, but the answers are all rubbish for my scenario (if they're not rubbish entirely), and (at least for the question here: jQuery UI drop event of droppable fires on sortable), the suggestion is just to turn off .sortable
entirely, which is most certainly not what I want to do.
Okay, I have this jquery (keep in mind if any options or html ids look silly, this is just for testing so I can try and figure this out):
$(function () {
$("#sortable").sortable({
revert: true
});
$("#draggable, #draggable2").draggable({
connectToSortable: "#sortable",
helper: "clone",
revert: "invalid"
});
$("#sortable").droppable({
drop: function (event, ui) { alert("done been triggered."); }
});
$("ul, li").disableSelection();
});
And here is the valid markup:
<div class="objectPaletteHolder">
<ul>
<li id="draggable" class="ui-state-highlight">Drag me down</li>
<li id="draggable2" class="ui-state-highlight">Drag this down, too</li>
<li id="draggable2" class="ui-state-highlight">Drag this down, also</li>
<li id="draggable2" class="ui-state-highlight">Drag this down, as well</li>
<li id="draggable2" class="ui-state-highlight">Drag this down, too</li>
<li id="draggable2" class="ui-state-highlight">Drag this down, too</li>
<li id="draggable2" class="ui-state-highlight">Drag this down, too</li>
<li id="draggable2" class="ui-state-highlight click">Drag this down, click</li>
<li id="draggable2" class="ui-state-highlight clicky">Drag this down, clicky</li>
</ul>
</div>
<div class="editContainer">
<ul id="sortable">
<li class="ui-state-default">Item 1</li>
<li class="ui-state-default">Item 2</li>
<li class="ui-state-default">Item 3</li>
<li class="ui-state-default">Item 4</li>
<li class="ui-state-default">Item 5</li>
</ul>
</div>
I do not have overlapping sortable
divs or anything like that, and I think I understand 'why' this is happening (because sortable
gets draggables properties by default?), I just can't seem to do anything about it.
The problem, of course, is that the...
drop: function (event, ui) { alert("done been triggered."); }
...is being triggered twice, when it is only needed once.
I would think that there would be a simple solution to this problem, for if this problem required a bunch of complex scripting to fix, than I would think that these particular jquery widgets wouldn't be worth all the trouble. Perhaps I am just confused?
Upvotes: 16
Views: 9127
Reputation: 5660
I had a similar problem. There were 2 droppable elements, one of them had relative position, and another one - absolute. They were not nested, but a part of the one with absolute postion was above the part of the one with relative position (in jQuery docs this is called "intersect"). When I moved a draggable element to the "absolute" droppable, drop event was trigged twice. I have been searching for a few days, but didn't find any solution.
Then I decided to make a simple general workaround. Looks not very attractive, but this will help in any situation with firing 2 drop events.
drop: function( e, ui ) {
if ( ! $('.already-dropped').length ) {
$('body').addClass('already-dropped');
setTimeout( function() {
$('.already-dropped').removeClass('already-dropped');
}, 100 );
// callback code...
}
}
Upvotes: 2
Reputation: 6276
Maybe I'm a little too late but I posted this hopefully it will help someone. This is the code I use. Basically, if the function is called twice, the interval between them should be quick (quicker than what human usually do) so I set the number to be 200 milliseconds.
I used localStorage to set a variable called "last_call". It's the time the function was called. In the next call, we will check if the function was called previously. If it wasn't called, the function will continue executing. If it was called, we will check when the last time it was called. If it was called within 200 milliseconds (which obviously machine call, not human call), we will not call it again.
var d = new Date();
var this_time = d.getTime();
if ( localStorage.getItem("last_call") != null)
{
if ((this_time - parseInt(localStorage.getItem("last_call"))) < 100)
{
return;
}
}
localStorage.setItem("last_call", this_time);
Upvotes: -2
Reputation: 16777
That's a known issue using both sortable
and droppable
on the same element.
You can use the sortable
's receive
event instead.
$("#sortable").sortable({
revert: true,
receive: function (event, ui) {
alert("receive been triggered.");
}
}).droppable({ });
Upvotes: 29