Search code examples
jqueryjquery-ui-sortablejquery-ui-droppable

jQuery sortable and droppable tolerance issue


We have a nested menu within our page where drag and drop is enabled to reorder and nest menu items..

There seems to be an issue (we are using jQuery 1.7.2 and UI 1.8.22) where if you have both a sortable and droppable, the tolerance for sorting is not consistent and is causing an issue.

An example is going to explain it better than I can...

http://jsfiddle.net/8fUxV/5/

I have just created the minimum needed to show the issue, and not the nested menus, merely the mechanism we are using to make it work.

Pick up "Item 4" and very slowly drag it upwards. 3 will become highlighted, meaning that is the target for the drop. Fine, but keep moving up until it is in the gap between 2 and 3. I want to drop it here and cause a sort. But if I do, as 3 is still highlighted, it will "drop" instead (and in our real code, create a nested menu).

There are actually a few pixels just before item 2, where you can get the desired effect. However, if you move down too far, it will again drop instead of sort.

Essentially, the issue is that I would think if the item were in the gap it should sort and only drop when I am over the other highlighted item.

I have a part workaround, that forces UI to recalculate the positions - uncomment the code in the "out" function.

Now whilst you still get the same problem if you drag 4 upwards, if you touch 2 and move back down into the gap, nothing is highlighted so it will sort correctly.

But the issue remains that the first drag upwards doesn't work as you would expect on that first rearrange.

(I did try adding the workaround into the _mousedrag of ui.sortable in the jquery.ui code, and it does solve the problem....but I have no idea what I'm doing in there :)

So I'm not sure if I am doing something wrong or if this a bug?

Has anyone come across something similar before I log a bug report?


Solution

  • After digging through the source, I found an option that fixes the issue.

    The problem is that the position are not calculated correctly when an item is moved around and the dummy placeholder is inserted within the list.

    You need to add this to your sortable,

    refreshPositions: true
    

    e.g.

    $("ul").sortable({
        helper: "original",
        refreshPositions: true,
        update: function(event, ui) {
           :
        }
    });
    

    This causes it to recalculate position on each and every mouse movement. Extremely inefficient, but it just won't work otherwise.