asked on
JQuery Multisortable.. does not work on multi selected Divs.. Fix or Different Drag and Drop
Having issues with JQuery multisortable.
Hey everyone.. Been using multisortable for this year and just not happy with it.
It has some update issues on the multiselect.
And when you try to resort multiple DIVs within the same DIV list the additional DIVs are always ignored. It does not catch them.
I have put a mock up together in the code section. Left to Right divs... seems to work ok.. although the order of updates are a bit odd. But I can live with that as it works for me.
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.js"></script>
<script src="media/js/ms/src/jquery.multisortable.js"></script>
</script>
</head>
<style>
#pagewrapper {
display: flex;
}
#left {
width: 50%;
border: 1px solid red;
}
#right {
width: 50%;
border: 1px solid green;
}
.selected {
border: 5px solid pink;
}
</style>
<body>
<h1>Test<h1>
<div id="pagewrapper">
LEFT div
<div id="left" class="connectedSortable" data-hid="left">
<div id="1" class="box" data-index="1" data-position="1">My div 1</div>
<div id="2" class="box" data-index="2" data-position="2">My div 2</div>
<div id="3" class="box" data-index="3" data-position="3">My div 3</div>
<div id="4" class="box" data-index="4" data-position="4">My div 4</div>
<div id="5" class="box" data-index="5" data-position="5">My div 5</div>
<div id="6" class="box" data-index="6" data-position="6">My div 6</div>
</div>
RIGHT div
<div id="Right" class="connectedSortable" data-hid="right">
</div>
</div>
</body>
<script>
$('#pagewrapper').ready(function() {
});
$('#pagewrapper').on('click', '.box', function MyDragnDrop() {
$( ".connectedSortable" ).multisortable({items: "div.box", connectWith: ".connectedSortable",selectedClass:"selected",
update: function(event) {
console.log("event: "+event.target.id);
$(this).children().each(function (index) {
var myindexdata = $(this).attr('data-index');
parentdiv = $(this).parent().attr('data-hid');
index = index+1;
$(this).attr('data-position', (index)).addClass('updated');
console.log("My Div: "+myindexdata+ " Index: "+index+ " data-position: "+$(this).attr('data-position')+ " parentdiv: " + parentdiv);
});
// Run my AJAX function with an array I build from the above just catching the changes etc...
}
});
});
</script>
</html>
HOWEVER, when you resort a multiselected group of DIVs within the same it never registers the additional selected DIVs and therefore I do not get my AJAX fired to update their positions which of course I need.
On the Left div just try moving 3 and 4 to the end for example. You will see the 3 Div gets registered but 4 is ignored so the event never occurs that I can catch and then fire to Ajax so my list is always wrong.
a) Any ideas on how to FIX the multisortable?
b) Different framework with same ability easy to implement into my existing projects which is maybe more popular?
Many thanks in advance
R
ASKER
$('#left').bind('contentchanged', function() {
// do something after the div content has changed
rerunme();
})
Rerunme just runs an iteration and reports.Again does not work.. ONLY works on a separate click event if I click to iterate through the children of the #left div.
Totally stuck.
Many thanks in advance
R
<script src="https://rawgithub.com/shvetsgroup/jquery.multisortable/master/src/jquery.multisortable.js"></script>
and made
https://jsfiddle.net/mplungjan/up8dvzqm/
Can you tell us exactly the steps you take to see the issue
ASKER
Put CONSOLE on.
Then drag 3 and 4 simultaneously from LEFT to RIGHT.
You will see the update event does NOT register the additional div 4.. however the RIGHT div corrects this by reporting 3 and 4.... as part of its update event. This means the end result is ok..
Reset.. Put console on.
Then drag 3 and 4 within LEFT div to beneath 6.. You will see in the CONSOLE it does not register the 4 div. This is NOT corrected like above as there are no other events for other divs firing so it means the order is always wrong when trying to do an ajax update.
Many thanks in advance
R
ASKER
Just correct that..
Thanks
R
"event: left"
"My Div: 1 Index: 1 data-position: 1 parentdiv: left"
"My Div: 2 Index: 2 data-position: 2 parentdiv: left"
"My Div: 3 Index: 3 data-position: 3 parentdiv: left"
"My Div: 5 Index: 4 data-position: 4 parentdiv: left"
"My Div: 6 Index: 5 data-position: 5 parentdiv: left"
"My Div: 4 Index: 6 data-position: 6 parentdiv: left"
in Chrome. What is wrong with that?
You want this instead?
"event: left"
"My Div: 1 Index: 1 data-position: 1 parentdiv: left"
"My Div: 2 Index: 2 data-position: 2 parentdiv: left"
"My Div: 5 Index: 4 data-position: 4 parentdiv: left"
"My Div: 6 Index: 5 data-position: 5 parentdiv: left"
"My Div: 3 Index: 3 data-position: 3 parentdiv: left"
"My Div: 4 Index: 6 data-position: 6 parentdiv: left"
DOM shows
<div id="left" class="connectedSortable ui-sortable" data-hid="left">
<div id="1" class="box ui-sortable-handle updated selected multiselectable-previous" data-index="1" data-position="1">My div 1</div>
<div id="2" class="box ui-sortable-handle updated" data-index="2" data-position="2">My div 2</div>
<div id="5" class="box ui-sortable-handle updated" data-index="5" data-position="4">My div 5</div>
<div id="6" class="box ui-sortable-handle updated" data-index="6" data-position="5">My div 6</div>
<div id="3" class="box ui-sortable-handle updated" data-index="3" data-position="3" style="">My div 3</div>
<div id="4" class="box ui-sortable-handle updated" data-index="4" data-position="6" style="">My div 4</div>
</div>
ASKER
The values you are getting are wrong.
The divs are ordered:
1,2,5,6,3,4 and as such I need to do an ajax update to save to the database the new positions.
Just like the values that you get... mine are 1,2,4,5,6,3
This is totally incorrect and therefore means the ordering and position cannot be updated correctly rendering the multiple drag and drop to resort completely useless.
I find the same thing happens even if I monitor the #left for changes.. It is only when I click and prompt to iterate through the children of #left on a click afterwards or on a timer does this work.
But of course I need this to occur as part of the update. I am unsure if it is the framework at fault, how the DOM changes or even my understanding.
Many thanks in advance.
R
ASKER
But I need the update event to be correct so my ajax database position update scripts work and update accordingly.
Right now they are only updating for Div 3 as per my example.
So I need to capture that order as part of the update event.
Many thanks
R
https://jsfiddle.net/mplungjan/913pch0a/
See the order
mine (using stop) works
https://jsfiddle.net/mplungjan/up8dvzqm/
ASKER
Leak I tried deactivate but it still returned the wrong order.
I can see this is working with stop Michel.
Just trying to work out now the best way to capture this DIV and then process all the positions so I can then run an ajax update
many thanks in advance.
R
ASKER
I.e. Div1, Div2, Div3, Div4, Div5 and on and on.
So I need to capture the DIV that has just been updated and then run some code to get the children and the index so I can then run an ajax update.
Many thanks
R
ASKER
I cannot static set #left .. I must dynamic understand this value from the very last drag and drop.
Many thanks in advance
R
ASKER
At the end of the UPDATE statement I store a variable LASTDIV with the parent div of the dropped box divs.
Then on the STOP statement I call my AJAX/OTHER function using the LASTDIV as a parameter.
OK cool.. I think I can sort this out now.
Many thanks in advance
R
click: function(e) { console.log(e.target.id)},
ASKER
I need to store in a variable from the UPDATE event as the event that triggered it is the LEFT div in our example
Thanks
R
ASKER
a) Dragging from one div to another.. All ok... Don't need the extra.
b) Dragging within a div - This is when this is needed.
So
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.js"></script>
<script src="media/js/ms/src/jquery.multisortable.js"></script>
</script>
</head>
<style>
#pagewrapper {
display: flex;
}
#left {
width: 50%;
border: 1px solid red;
}
#right {
width: 50%;
border: 1px solid green;
}
.selected {
border: 5px solid pink;
}
</style>
<body>
<h1>Test<h1>
<div id="pagewrapper">
<div id="testbut1">testbut1</div>
LEFT div
<div id="left" class="connectedSortable" data-hid="left">
<div id="1" class="box" data-index="1" data-position="1">My div 1</div>
<div id="2" class="box" data-index="2" data-position="2">My div 2</div>
<div id="3" class="box" data-index="3" data-position="3">My div 3</div>
<div id="4" class="box" data-index="4" data-position="4">My div 4</div>
<div id="5" class="box" data-index="5" data-position="5">My div 5</div>
<div id="6" class="box" data-index="6" data-position="6">My div 6</div>
</div>
RIGHT div
<div id="right" class="connectedSortable" data-hid="right">
</div>
</div>
</div>
</body>
<script>
$('#pagewrapper').ready(function() {
});
let lastdiv = '';
let clickdiv = '';
$('#pagewrapper').on('click', '.box', function MyDragnDrop() { $( ".connectedSortable" ).multisortable({items: "div.box", connectWith: ".connectedSortable",selectedClass:"selected",
click: function(e,item) {
clickdiv = $(item).parent().attr('data-hid');
},
stop: function(e){
if (lastdiv.length > 0)
{
rerunme(lastdiv,clickdiv);
}
},
update: function(event) {
$(this).children().each(function (index) {
var myindexdata = $(this).attr('data-index');
parentdiv = $(this).parent().attr('data-hid');
index = index+1;
$(this).attr('data-position', (index)).addClass('updated');
console.log("My Div: "+myindexdata+ " Index: "+index+ " data-position: "+$(this).attr('data-position')+ " parentdiv: " + parentdiv);
lastdiv = parentdiv;
console.log("parentdiv: "+ parentdiv);
});
// Run some AJAX position scripts.
}
});
});
function rerunme(mydiv,mydiv2){
$('#'+mydiv).children().each(function (index) {
var myindexdata = $(this).attr('data-index');
parentdiv = $(this).parent().attr('data-hid');
if (mydiv == mydiv2)
{
console.log("rerunme - My Div: "+myindexdata+ " Index: "+index+ " data-position: "+$(this).attr('data-position')+ " parentdiv: " + parentdiv);
// Run my AJAX function with an array I build from the above just catching the changes etc...
}
else
{
console.log("They are different - DO NOT RUN");
}
lastdiv = '';
clickdiv = '';
});
}
</script>
</html>
Many thanks for your help.Anyway you would improve this? Disappointed I am running 2x lots of AJAX updates unnecessarily just because I am cleaning up afterwards.
Many thanks
R
ASKER
NOPE it would not.. as I still need original AJAX running for when you drop between Divs.. unless I run completely different there and utilise the RECEIVE: statement.
That is my only thoughts on improvement.
R
Here is the running example of your latest code
https://jsfiddle.net/mplungjan/y2pze1nh/
What SHOULD it do and how is it failing?
What is rerunme supposed to do that it is not
ASKER
For clarity.. my latest version of the code.. is ALL GOOD. I have implemented already into my development project. I am just asking if any improvements?
So ---
Rerunme is iterating through the LASTDIV that had an event... so this would be the DIV that had the order change.
It then collects the box DIV ID and INDEX number... and then does an AJAX update meaning that when the order is incorrect for multiple divs being reordered it corrects it.
First go with the UPDATE event I would receive 1,2,4,5,6,3
This is wrong.. the DOM is right.. but the events are wrong.
Rerunme then reprocesses (and sends an ajax db update) with the order 1,2,5,6,3,4
This means my database is up to date and reflects the DOM.
It is just a shame that I have to run 2x AJAX updates to correct a reorder within the same DIV.
But I can live with this. I just wanted to know if there were any obvious improvements.
Many thanks
R
stop: function(event) { // stop or update should work with a timer
setTimeout(function() { // the ugly way
// do your ajax here
}, 100); // wait 100ms, so you got the DOM right
}
Why would we need a timer. In my test, stop gets the DOM correctly immediately@Michel, you right, I see stop event is fired after DOM fully updated.
@Romolo, my two cents :
Don't do too much stuff on client side, I would just use stop event, loop over to get id to build and array and send this array to server, for example : [1,2,5,6,3,4]
If needed, server code could be 1 000 000 lines of code to update database... if needed...
I would keep client side as cleanest as possible.
<html>
<head>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
#pagewrapper {
display: flex;
}
#left {
width: 50%;
border: 1px solid red;
}
#right {
width: 50%;
border: 1px solid green;
}
.selected {
border: 5px solid pink;
}
</style>
</head>
<body>
<h1>Test</h1>
<div id="pagewrapper">
<div id="testbut1">testbut1</div>
LEFT div
<div id="left" class="connectedSortable" data-hid="left">
<div id="1" class="box" data-index="1" data-position="1">My div 1</div>
<div id="2" class="box" data-index="2" data-position="2">My div 2</div>
<div id="3" class="box" data-index="3" data-position="3">My div 3</div>
<div id="4" class="box" data-index="4" data-position="4">My div 4</div>
<div id="5" class="box" data-index="5" data-position="5">My div 5</div>
<div id="6" class="box" data-index="6" data-position="6">My div 6</div>
</div>
RIGHT div
<div id="right" class="connectedSortable" data-hid="right"></div>
</div>
<script src="//code.jquery.com/jquery-3.6.0.js"></script>
<script src="//code.jquery.com/ui/1.13.0/jquery-ui.js"></script>
<script src="//rawgit.com/shvetsgroup/jquery.multisortable/master/src/jquery.multisortable.js"></script>
<script>
$('#pagewrapper').ready(function() {
}).on('click', '.box', function MyDragnDrop() {
$( ".connectedSortable" ).multisortable({
items: "div.box",
connectWith: ".connectedSortable",
selectedClass: "selected",
stop: function(e) {
//console.log($(e.target).html());
$.post("/path/to/save/box/order",{ array_Id_new_order : $("div.box",e.target).map((i,box)=>box.id).toArray() });
},
});
});
</script>
</body>
</html>
$("div.box",e.target).map((i,box)=>box.id).toArray()
Why not .get() ?
ASKER
@michel .. STOP seems to work so without over complicating I will just stick with this for now rather than reduce down the ajax calls at least for this dev copy and evaluate.
Many thanks for all the help
R
ASKER
But as part of that UPDATE event I cannot get the additional dragged divs.
Many thanks in advance
R