0

I'm implementing sortable plugin of jQuery UI. There are two columns and we can drag and drop an element from one column to another column. I have the following javascript code:

$(function () {
     $("#sortable1, #sortable2").sortable({
         connectWith: ".connectedSortable",
         update: function () {
             var order1 = $('#sortable1').sortable('toArray').toString();
             var order2 = $('#sortable2').sortable('toArray').toString();

             alert("Order 1:" + order1 + "\n Order 2:" + order2); 
             $.ajax({
                 type: "POST",
                 url: "/echo/json/",
                 data: "order1=" + order1 + "&order2=" + order2,
                 dataType: "json",
                 success: function (data) {
                 }
             });
         }
     }).disableSelection();
 });

And HTML:

<ul id="sortable1" class="connectedSortable">
  <li class="ui-state-default" id='item1'>Item 1</li>
  <li class="ui-state-default" id='item2'>Item 2</li>
  <li class="ui-state-default" id='item3'>Item 3</li>
  <li class="ui-state-default" id='item4'>Item 4</li>
  <li class="ui-state-default" id='item5'>Item 5</li>
</ul>
 
<ul id="sortable2" class="connectedSortable">
  <li class="ui-state-highlight" id='item6'>Item 6</li>
  <li class="ui-state-highlight" id='item7'>Item 7</li>
  <li class="ui-state-highlight" id='item8'>Item 8</li>
  <li class="ui-state-highlight" id='item9'>Item 9</li>
  <li class="ui-state-highlight" id='item10'>Item 10</li>
</ul>

From above javascript, I can get the order of column 1 and column 2 after change as a whole. However, I would like to know the individual item that has been changed. Like, in this image below, I have Item3 dragged from Column 1 to Column 2. I want to get output like - Item3_before=Column1,Item3_after=Column2. enter image description here

In the javascript code above, by using start event like the update event, we can get the Before status of the elements, but not the individual element; it gives before status of all elements.

Community
  • 1
  • 1
Martin
  • 209
  • 1
  • 12
  • You want to know when a list receives a new item? OR do you want to know the order or each list before and after a sort to compare? – Twisty Nov 28 '16 at 00:37
  • I want to know the status of the item before and after. Like in above example, Item 3 has been changed from Column 1 to Column 2. So, I would like to know the before status of Item 3 as Column 1 and after status as Column 2. – Martin Nov 28 '16 at 03:53
  • I would capture the array in `start` and then again in `update`. Then compare the 2 and determine what item was moved. – Twisty Nov 28 '16 at 05:05

1 Answers1

1

Few steps to take. I setup an Object to store the values at Activation, Pre-Sorting, and Post-Sorting for both lists. Once that was done, I used this method to determine the difference: JavaScript array difference

Working Example: https://jsfiddle.net/Twisty/kfedekmj/

jQuery

$(function() {
  var items = {
    "act": {
      1: [],
      2: []
    },
    "pre": {
      1: [],
      2: []
    },
    "post": {
      1: [],
      2: []
    }
  }

  function log(et) {
    if (!et) {
      console.log("Activation");
      console.log(" - order1: ", items.act[1].toString());
      console.log(" - order2: ", items.act[2].toString());
    }
    if (et == "sortstart") {
      console.log("Pre-Sort");
      console.log(" - order1: ", items.pre[1].toString());
      console.log(" - order2: ", items.pre[2].toString());
    }
    if (et == "sortupdate") {
      console.log("Post-Sort");
      console.log(" - order1: ", items.post[1].toString());
      console.log(" - order2: ", items.post[2].toString());
    }
  }

  function determineChange(a1, a2) {
    var a = {},
      diff = [],
      i = 0;

    for (i = 0; i < a1.length; i++) {
      a[a1[i]] = true;
    }

    for (i = 0; i < a2.length; i++) {
      if (a[a2[i]]) {
        delete a[a2[i]];
      } else {
        a[a2[i]] = true;
      }
    }

    $.each(a, function(k, v) {
      diff.push(k);
    });    

    return diff[0];
  }

  $("#sortable1, #sortable2").sortable({
    connectWith: ".connectedSortable",
    start: function(e, ui) {
      // Start of Sort Order
      items.pre[1] = $('#sortable1').sortable('toArray')
      items.pre[2] = $('#sortable2').sortable('toArray')
      log(e.type);
    },
    update: function(e, ui) {
      // End of Sort Order
      items.post[1] = $('#sortable1').sortable('toArray');
      items.post[2] = $('#sortable2').sortable('toArray');
      log(e.type);
      /*
      $.ajax({
        type: "POST",
        url: "/echo/json/",
        data: "order1=" + order1 + "&order2=" + order2,
        dataType: "json",
        success: function(data) {}
      });
      */
      var newItem1 = determineChange(items.pre[1], items.post[1]);
      console.log(newItem1);
    }
  }).disableSelection();

  // Activation Order
  items.act[1] = $('#sortable1').sortable('toArray');
  items.act[2] = $('#sortable2').sortable('toArray');

  log();
});

Leaving them as Arrays makes it a lot easier to compare and manipulate. Storing each part in an object simply makes it easier to gather all the info.

The only thing to be mindful of is that update runs 2 times. When an item is removed from list 1, out and added to list 2, receive. It does not make a difference in the end, but it's something to be mindful of just in case.

Community
  • 1
  • 1
Twisty
  • 30,304
  • 2
  • 26
  • 45
  • This is quite helpful. This now gives which item has been moved. Like, pre-sort, post-sort and item moved. The previous and current column of item is still unknown it seems. Like, item 1 is moved from column 1 to column 2, however, only item 1 is logged. The logging is great, it'd be better if we can get the following output: - itemchanged: Item1 - Before: Column 1 - After: Column 2 – Martin Nov 28 '16 at 22:02
  • @Martin you could do that. You can also leverage the `out` and `receive` events to determine when an item was moved or adjust the compare function to see which list lost/gained an item via comparing each array length. – Twisty Nov 28 '16 at 22:09
  • @Martin Here's a simple update: https://jsfiddle.net/Twisty/kfedekmj/8/ – Twisty Nov 28 '16 at 23:53
  • Works like a charm. Thanks! – Martin Nov 29 '16 at 00:36
  • Is there a way to get sortable1 instead of order1 and sortable2 instead of order2? I mean not hardcoded but from the corresponding ID. Also, can we also do for 3 or more columns? Of course using the ID which would be sortable1, sortable2 and sortable3 and so on. – Martin Nov 29 '16 at 02:32
  • @Martin yes that's possible. Use `.attr ("id")` – Twisty Nov 29 '16 at 02:34
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/129311/discussion-between-martin-and-twisty). – Martin Nov 29 '16 at 05:12
  • thanks, however I'm not getting the required output. Can you share the jsfiddle if possible? – Martin Nov 29 '16 at 13:42
  • @Martin not sure I understand what you're looking for but maybe this will help: https://jsfiddle.net/Twisty/kfedekmj/12/ – Twisty Nov 29 '16 at 18:22
  • yeah thats what I was looking for. In addition to that, I need to have multiple columns and I will make that dynamic. I tried to do for 3 columns on https://jsfiddle.net/kfedekmj/14/ but I'm not quite sure on the things that I need to change on Javascript. Any additional help is appreciated for multiple columns! – Martin Nov 29 '16 at 21:17
  • @Martin lots, but mostly just adding the 3rd column storage and a few other steps. Take a stab at it. If you get stuck on something, start a new question. – Twisty Nov 29 '16 at 23:07
  • just a gentle reminder.. if you get a chance to look at it to give an example, that'd be a life saver for me! Waiting for it.. – Martin Nov 30 '16 at 20:04
  • @Martin Do remember that most of the people here are volunteering to help others out. Take a look here: https://jsfiddle.net/Twisty/kfedekmj/16/ – Twisty Nov 30 '16 at 20:16
  • Can also do this with `ui.sender`like so: https://jsfiddle.net/Twisty/kfedekmj/16/ – Twisty Nov 30 '16 at 20:21
  • you're a life savor. Thanks! – Martin Dec 01 '16 at 00:39