I'm using jQuery UI sortable to sort connected lists. The update event appears to be running twice.
Here is the full sortable call:
$(".pageContent").sortable({
handle: ".quesText",
connectWith: ".pageContent",
containment: "section",
start: function(e, ui){
ui.placeholder.height(ui.item.height());
},
placeholder: "sortable-placeholder",
opacity: 0.5,
cursor: "move",
cancel: "input, select, button, a, .openClose",
update: function(e, ui){
var thisItem = ui.item;
var next = ui.item.next();
var prev = ui.item.prev();
var thisNumber = thisItem.find(".quesNumb");
var nextNumber = next.find(".quesNumb");
var prevNumber = prev.find(".quesNumb");
var tn = parseInt(thisNumber.text());
var nn = parseInt(nextNumber.text());
var pn = parseInt(prevNumber.text());
var quesNumbs = $(".quesNumb");
var newItemId = thisItem.attr("id").replace(/_\d+$/, "_");
//test if we are dragging top down
if(ui.position.top > ui.originalPosition.top){
quesNumbs.each(function(i){
var thisVal = parseInt($(this).text());
var grandparent = $(this).parent().parent();
var grandId = grandparent.attr("id").replace(/_\d+$/, "_");
if(thisVal > tn && (thisVal <= pn || thisVal <= (nn - 1))){
$(this).text(thisVal - 1 + ".");
grandparent.attr("id",grandId + (thisVal - 1));
}
});
if(!isNaN(pn) || !isNaN(nn)){
if(!isNaN(pn)){
//for some reason when there is a sender pn gets updated, so we check if sender exists
//only occurs sorting top down
if($.type(ui.sender) !== "null"){
var senderId = ui.sender.attr("id");
thisNumber.text(pn + 1 + ".");
thisItem.attr("id",senderId + "_" + (pn + 1));
alert(thisItem.attr("id"));
}
else {
thisNumber.text(pn + ".");
thisItem.attr("id",newItemId + pn);
alert(thisItem.attr("id"));
}
}
else {
thisNumber.text(nn - 1 + ".");
}
}
else {
//something will happen here
}
}
//otherwise we are dragging bottom up
else {
quesNumbs.each(function(i){
var thisVal = parseInt($(this).text());
if(thisVal < tn && (thisVal >= nn || thisVal >= (pn + 1))){
$(this).text(thisVal + 1 + ".");
}
});
if(!isNaN(pn) || !isNaN(nn)){
if(!isNaN(pn)){
thisNumber.text(pn + 1 + ".");
}
else {
thisNumber.text(nn + ".");
}
}
else {
//something will happen here
}
}
}
});
Here is the part that seems to run twice:
if($.type(ui.sender) !== "null"){
var senderId = ui.sender.attr("id");
thisNumber.text(pn + 1 + ".");
thisItem.attr("id",senderId + "_" + (pn + 1));
alert(thisItem.attr("id"));
}
else {
thisNumber.text(pn + ".");
thisItem.attr("id",newItemId + pn);
alert(thisItem.attr("id"));
}
I am expecting to only get one alert
as ui.sender
is null
when the sorting stays inside the same list. When an item leaves a list to go to another then ui.sender
will no longer be null
.
The problem is I will get 2 alert messages when I move an item to a new list. Its as if ui.sender is set after the update function runs once then it runs through the update function again. Obviously this is no good because I am overwriting data that should not necessarily be overwritten.
If that is the case how should I rewrite my code to avoid overwriting data?
EDIT
I believe the update event is called each time a list DOM is changed, not just the DOM in general. So for each list that has a DOM change the update runs. When I move one item to a new list I am updating two lists.
So I guess the new question is: how do I rewrite this code knowing it will fire two times? Is there a combination of Receive and Remove events that could achieve this?
I have posted the answer here: jquery Sortable connectWith calls the update method twice
You can combine the remove and receive and create an array which will hold changes and than post it to the server as JSON.
Demo: http://jsfiddle.net/r2d3/p3J8z/
HTML:
<div class="container">
<div class="step" id="step_1">
<h2 class="title">Step 1</h2>
<div class="image" id="image_10">Image 10</div>
<div class="image" id="image_11">Image 11</div>
<div class="image" id="image_12">Image 12</div>
</div>
<div class="step" id="step_2">
<h2 class="title">Step 2</h2>
<div class="image" id="image_21">Image 21</div>
<div class="image" id="image_22">Image 22</div>
<div class="image" id="image_23">Image 23</div>
</div>
JS:
$(function(){
/* Here we will store all data */
var myArguments = {};
function assembleData(object,arguments)
{
var data = $(object).sortable('toArray'); // Get array data
var step_id = $(object).attr("id"); // Get step_id and we will use it as property name
var arrayLength = data.length; // no need to explain
/* Create step_id property if it does not exist */
if(!arguments.hasOwnProperty(step_id))
{
arguments[step_id] = new Array();
}
/* Loop through all items */
for (var i = 0; i < arrayLength; i++)
{
var image_id = data[i];
/* push all image_id onto property step_id (which is an array) */
arguments[step_id].push(image_id);
}
return arguments;
}
/* Sort images */
$('.step').sortable({
connectWith: '.step',
items : ':not(.title)',
/* That's fired first */
start : function( event, ui ) {
myArguments = {}; /* Reset the array*/
},
/* That's fired second */
remove : function( event, ui ) {
/* Get array of items in the list where we removed the item */
myArguments = assembleData(this,myArguments);
},
/* That's fired thrird */
receive : function( event, ui ) {
/* Get array of items where we added a new item */
myArguments = assembleData(this,myArguments);
},
update: function(e,ui) {
if (this === ui.item.parent()[0]) {
/* In case the change occures in the same container */
if (ui.sender == null) {
myArguments = assembleData(this,myArguments);
}
}
},
/* That's fired last */
stop : function( event, ui ) {
/* Send JSON to the server */
$("#result").html("Send JSON to the server:<pre>"+JSON.stringify(myArguments)+"</pre>");
},
});
});
Full explanation of the solution: http://r2d2.cc/2014/07/22/jquery-sortable-connectwith-how-to-save-all-changes-to-the-database/
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