I am using drag and drop functionality to allow users to order elements on a page. I have several <ul>
elements with <li>
elements inside of them (all <ul>
contain 3 <li>
elements) where each unordered list corresponds to a month, so
<ul class="dragable" id="month-june">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="dragable" id="month-july">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="dragable" id="month-august">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<!-- etc.. -->
I want to somehow sort all of the lists once .drop()
event occurs (basically users drop item in place after dragging it). I'm changing list positions in dom so they are always ordered there, for example if Item 3 from august is moved between item 1 and item 2 in july it will look like this:
<ul class="dragable" id="month-july">
<li>Item 1</li>
<li>Item 3</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
Now I need to figure out how to push Item 3 from july down to augusts unordered list and also push down all other items after it. This should have vice versa effects if for example Item 1 from june is draged into july between item 2 and item 3, in this case everything above it should shift left. Therefore I need to have 3 items in all list at any given time.
Here is image further showing it, that hopefully explains it better: (Consider middle section as initial and than arrows show where item is dragged and what happens to lists before and after it depending on position)
Could this be done without using ids or classes, but relying on next and previous elements (unordered lists), as I don't know exactly what months follow what in this case.
Here is very simple js fiddle with drag and drop behaviour: DEMO
Updates on Drop
$(".sortable-queue").sortable({
revert: true,
scroll: false,
connectWith: ".connected-sortable",
placeholder: "item-dragable-placeholder",
receive: function (event, ui) {
var target = $(event.target).parent().parent();
var source = ui.sender.parent().parent();
var children = target.parent().children();
var start = children.index(source);
var end = children.index(target);
// bubble up?
if (start < end) {
for (var i = start; i < end; i++) {
$(children[i]).find("ul").append($(children[i + 1]).find("li").first().detach())
}
}
// bubble down?
else if (start > end) {
for (var i = start; i > end; i--) {
$(children[i]).find("ul").prepend($(children[i - 1]).find("li").last().detach())
}
}
// same pulldown
else
return;
}
}).disableSelection();
All it does is identify the div wrappers for the source and target uls. It then uses this to figure out if the target ul is above or below the source ul.
If it is below, it steps through all the wrappers from source to target, grabbing the first li from the succeeding wrapper and adding it to its end.
If it is above, the same thing happens, the only difference being it's picked from the end and added to the start.
If the source and target wrapper is the same, we don't need to do anything.
Fiddle - https://jsfiddle.net/ajdw2u0b/
Updates When Dragging
var source;
$(".sortable-queue").sortable({
revert: true,
scroll: false,
connectWith: ".connected-sortable",
placeholder: "item-dragable-placeholder",
start: function(event, ui) {
source = ui.item.parent().parent().parent();
},
over: function (event, ui) {
var target = $(event.target).parent().parent();
var children = target.parent().children();
var start = children.index(source);
var end = children.index(target);
// same pulldown
if (start === end) {
console.log(start)
return;
}
// bubble up?
else if (start < end) {
for (var i = start; i < end; i++) {
$(children[i]).find("ul").append($(children[i + 1]).find("li:not(.ui-sortable-helper):not(.item-dragable-placeholder)").first().detach())
}
}
// bubble down?
else if (start > end) {
for (var i = start; i > end; i--) {
$(children[i]).find("ul").prepend($(children[i - 1]).find("li:not(.ui-sortable-helper):not(.item-dragable-placeholder)").last().detach())
}
}
source = target;
}
}).disableSelection();
The logic is pretty much the same. The only differences are that
over
(when you drag your item over a drop target). Note that you have to exclude the element being dragged and the place holder when picking an element to detach.
Fiddle - https://jsfiddle.net/f4655x9n/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With