Search code examples
jquery-uijquery-ui-sortable

Programmatically sort jquery-ui sortable?


I have a bunch of divs inside a display:flex parent div. The parent div is sortable with jquery-ui's sortable function.

As well as allowing the user to sort, I would like to add some buttons that do an animated sort.

For example, with this HTML:

<div class="sortable">
  <div id="div1"></div>
  <div id="div2"></div>
  <div id="div3"></div>
  <div id="div4"></div>
  <div id="div5"></div>
</div>

I would like a button that when pressed would animate moving div1 to be between div4 and div5, moving smoothly (in fact, a little erratically as if it were being moved by hand would be even better) and shifting all the divs it passes, so it looks as if it were being moved by hand.

Is this possible using jquery-ui's sortable(), or am I better off building a custom solution?


Solution

  • Consider the following example.

    $(function() {
      function arrange(obj, pre) {
        obj = $(obj);
        var t = $("[id^='div']:eq(" + pre + ")");
        obj.animate({
          top: t.position().top + "px"
        }, {
          duration: 1000,
          step: function(i) {
            $(this).position({
              my: "left top",
              at: "left bottom",
              of: t,
            });
          },
          complete: function() {
            obj.detach().css("top", "").insertAfter(t);
          }
        });
      }
    
      $(".sortable").sortable().disableSelection();
    
      $("#arrange").click(function() {
        arrange($("#div1"), 3);
      });
    });
    .sortable {
      list-style-type: none;
      margin: 0;
      padding: 0;
      position: relative;
    }
    
    .sortable div {
      margin: 0 3px 3px 3px;
      padding: 0.4em;
      height: 18px;
    }
    <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <div class="sortable">
      <div id="div1" class="ui-state-default">Item 1</div>
      <div id="div2" class="ui-state-default">Item 2</div>
      <div id="div3" class="ui-state-default">Item 3</div>
      <div id="div4" class="ui-state-default">Item 4</div>
      <div id="div5" class="ui-state-default">Item 5</div>
    </div>
    <button class="btn" id="arrange">Arrange</button>

    Built from https://css-tricks.com/jquery-ui-position-function/

    Update

    $(function() {
      function swap(a, b, ms) {
        console.log("Swap:", a.attr("id"), "with", b.attr("id"));
        a.animate({
          top: b.position().top + "px"
        }, {
          duration: ms,
          step: function(i) {
            $(this).position({
              my: "left top",
              at: "left bottom",
              of: b,
            });
          },
          complete: function() {
            a.detach().css("top", "").insertAfter(b);
          }
        });
      }
    
      function arrangeAfter(a, b) {
        var n = a.next();
        for (var c = parseInt(n.attr("id").slice(-1)); n.index() <= b.index(); c++) {
          swap(a, n, 400);
          n = $("#div" + (c + 1));
        }
      }
    
      $(".sortable").sortable().disableSelection();
    
      $("#arrange").click(function() {
        arrangeAfter($("#div1"), $("#div4"));
      });
    });
    .sortable {
      list-style-type: none;
      margin: 0;
      padding: 0;
      position: relative;
    }
    
    .sortable div {
      margin: 0 3px 3px 3px;
      padding: 0.4em;
      height: 18px;
    }
    <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <div class="sortable">
      <div id="div1" class="ui-state-default">Item 1</div>
      <div id="div2" class="ui-state-default">Item 2</div>
      <div id="div3" class="ui-state-default">Item 3</div>
      <div id="div4" class="ui-state-default">Item 4</div>
      <div id="div5" class="ui-state-default">Item 5</div>
    </div>
    <button class="btn" id="arrange">Arrange</button> <button class="btn" id="reset">Reset</button>