SortableJS support

The Sircl extended library provides basic support for drag & drop. This support is insufficient to easily maintain a sorted list. The Sircl extension for Sortable makes it easy to integrate Sortable and provide sorting functionality through drag & drop.

The Sircl extended library provides basic support for drag & drop, but this support is insufficient to easily maintain a sorted list.

Sortable is an MIT licensed JavaScript library for sortable drag-and-drop lists.

For more information on Sortable, see: https://github.com/SortableJS/Sortable.

For demonstrations of Sortable, see: http://sortablejs.github.io/Sortable/.

The Sircl extension for Sortable makes it easy to integrate Sortable and provide sorting functionality through drag & drop for the most common scenarios.

Setup

Sortable is a stand-alone library with no further requirements. To setup Sortable in combination with Sircl, you need to install following files in order:

  • Cascading style sheets
    • sircl.css
  • Javscript:
    • jquery.js
    • Sortable.js
    • sircl.js
    • sircl-sortable.js

You can replace sircl.js by sircl-bundle.js, and/or add more Sircl libraries.

Sortable lists

To create a sortable list, simply add one of the following classes to the parent of the elements that should be sortable: onsort, onsort-move, onsort-copy or onsort-submit.

For simple sortable behavior that does not trigger a form submission, use the onsort-move class. In the following example, the parent element of 3 (Bootstrap styled) alerts has the onsort-move class which makes the alerts sortable:

<div class="onsort-move">
  <div class="alert alert-info">
    Monday
  </div>
  <div class="alert alert-info">
    Tuesday
  </div>
  <div class="alert alert-info">
    Wednesday
  </div>
</div>

No server call is envolved, hence, the server will only be aware of the sort operations once, for instance, the surrounding form is submitted. In addition, the server will have to figure out by itself the order of items. It could do so by analyzing the set and order of form fields received.

Submitting on sort

To inform the server of a sort operation right-away, add the onsort-submit class (you may remove the onsort-move class as it is implied as default sorting behavior).

The sortable list should then be surrounded by a FORM. The form can then contain input fields (hidden or not), which will be filled-in before submitting the form, based on their class. For instance, an input field with the class onsort-setfromindex will on sorting, and before the form is submitted, get the original index (0-based) position of the sorted element.

Following input field classes are supported:

Class name Value
onsort-setfromlist The name of the list the sorted element was taken from.
onsort-setfromindex The index position (0-based) of the sorted element before the sorting.
onsort-settolist The name of the list the sorted element was placed to.
onsort-settoindex The index position (0-based) of the sorted element after the sorting.

(Lists and list names are covered later.)

In the following example, every sort operation in the list will trigger a submission of the form where the input fields fromindex and toindex will tell the server which element to move where:

<form action="/Sort" method="post">
  <input type="hidden" class="onsort-setfromindex" name="fromindex" />
  <input type="hidden" class="onsort-settoindex" name="toindex" />
  <div class="onsort-submit">
    <div class="alert alert-info">
      Monday
    </div>
    <div class="alert alert-info">
      Tuesday
    </div>
    <div class="alert alert-info">
      Wednesday
    </div>
  </div>
</form>

The server can respond to the form submission by returning new (sorted) content. Or the server can respond with status 204-NoContent when the client-side HTML code does not need other alteration than was already done by the sorting. Not that in that case, the onsort-* fields are not reset and they may still have values left from a previous sorting. These values will be overwritten on a new sorting, but not when the form is submitted otherwise.

The element having the onsort-submit class can also define custom formaction, formmethod, formenctype, formtarget and formnovalidate attributes. For instance to differentiate regular form submits from sorting form submits.

Serverside pseudo-code to handle the list sorting could look like (assuming list indexes are 0-based in your serverside language):

public HttpResponse HandleRequest(int fromIndex, int toIndex) {
  var movedItem = list.At(fromIndex);
  list.RemoveAt(fromIndex);
  list.InsertAt(toIndex, movedItem);
  persistChanges();
  return new HttpResponse(204);
}

If we are sorting a list based on items that have a 0-based Order field, our server-side code would have to update that field in a way similar to the following pseudo-code:

public HttpResponse HandleRequest(int fromIndex, int toIndex) {
  if (toindex < fromindex) {
    foreach (item in list.Where(item.Order >= toindex and item.Order <= fromindex)) {
      if (item.Order == fromindex) {
        item.Order = toindex;
      } else {
        item.Order++;
      }
    }
  } else {
    foreach (item in list.Where(item.Order <= toindex and item.Order >= fromindex)) {
      if (item.Order == fromindex) {
        item.Order = toindex;
      } else {
        item.Order--;
      }
    }
  }
  persistChanges();
  return new HttpResponse(204);
}

Sorting multiple lists

If the form contains multiple lists, lists can be named using the sort-name attribute. The name of the list that was sorted can then be passed to the server by means of a field decorated with the onsort-setfromlist class as in:

<form action="/Sort" method="post">
  <input type="hidden" class="onsort-setfromlist" name="list" />
  <input type="hidden" class="onsort-setfromindex" name="fromindex" />
  <input type="hidden" class="onsort-settoindex" name="toindex" />
  <div class="row">
    <div class="col">
      <div class="onsort-submit" sort-name="weekdays">
        <div class="alert alert-warning">
          Monday
        </div>
        <div class="alert alert-warning">
          Tuesday
        </div>
        <div class="alert alert-warning">
          Wednesday
        </div>
      </div>
    </div>
    <div class="col">
      <div class="onsort-submit" sort-name="months">
        <div class="alert alert-success">
          January
        </div>
        <div class="alert alert-success">
          February
        </div>
        <div class="alert alert-success">
          March
        </div>
      </div>
    </div>
  </div>
</form>

An alternative way to detect which list was sorted, is to use a formaction attribute on the list:

<form action="/Submit" method="post">
  <input type="hidden" class="onsort-setfromindex" name="fromindex" />
  <input type="hidden" class="onsort-settoindex" name="toindex" />
  <div class="row">
    <div class="col">
      <div class="onsort-submit" formaction="/SortWeekdays">
        <div class="alert alert-warning">
          Monday
        </div>
        <div class="alert alert-warning">
          Tuesday
        </div>
        <div class="alert alert-warning">
          Wednesday
        </div>
      </div>
    </div>
    <div class="col">
      <div class="onsort-submit" formaction="/SortMonths">
        <div class="alert alert-success">
          January
        </div>
        <div class="alert alert-success">
          February
        </div>
        <div class="alert alert-success">
          March
        </div>
      </div>
    </div>
  </div>
</form>

Moving between lists

The Sortable library, and the Sircl extension for Sortable, make it also possible to drag & drop elements from one list to the other. By default, when a webpage contains 2 or more lists, elements are only draggable/sortable within their own list.

To have one list accept elements from another list to be dropped on, the accepting list must have the onsort-accept attribute listing the names of the other lists (separated by spaces) from where to accept elements from. The own list is always accepted and does not need to be named.

If the lists are inside a form and have the onsort-submit class, the input fields .onsort-setfromlist and .onsort-settolist will contain the name of the list the element was dragged from and the name of the list the element was dragged to respectively, allowing the server to identify the user action correctly.

In the following example, two lists are maintained: absences and presences. Names can be dragged from one list to the other (and sorted inside the lists):

<form action="/UpdatePresences" method="post">
  <input type="hidden" class="onsort-setfromlist" name="fromlist" />
  <input type="hidden" class="onsort-setfromindex" name="fromindex" />
  <input type="hidden" class="onsort-settolist" name="tolist" />
  <input type="hidden" class="onsort-settoindex" name="toindex" />
  <div class="row">
    <div class="col">
      <p>Absent:</p>
      <div class="onsort-submit" sort-name="absence" onsort-accept="presence">
        <div class="alert alert-warning">
          Mary
        </div>
        <div class="alert alert-warning">
          Tom
        </div>
      </div>
    </div>
    <div class="col">
      <p>Present:</p>
      <div class="onsort-submit" sort-name="presence" onsort-accept="absence">
        <div class="alert alert-success">
          Joan
        </div>
      </div>
    </div>
  </div>
</form>

When elements are dragged from a list A to a list B, the sort-submit class on list A (the originating list) determines whether and how a form submission is done. The following serverside pseudo-code handles sortings between lists:

public HttpResponse HandleRequest(string fromList, int fromIndex, string toList, int toIndex) {
  var fromList = getListByName(fromList);
  var toList = getListByName(toList);
  var movedItem = fromList.At(fromIndex);
  fromList.RemoveAt(fromIndex);
  toList.InsertAt(toIndex, movedItem);
  persistChanges();
  return new HttpResponse(204);
}

Copying between lists

By default, items are moved inside their list or from one list to the other. When dragging an element from one list to another, it is also possible to choose the element to be copied (cloned) instead of moved.

To trigger copy behavior, the originating list should have the onsort-copy class (which on its own makes a list sortable and which can be combined with the onsort-submit class).

In the following example, elements in both lists can be sorted. Elements are not copied or cloned when sorted inside their originating list. Elements can also be dragged from the first (left) list to the second (right) list. When this happens, a copy of the element is placed in the second list. Elements are not draggable from the second (right) to the first (left) list (as the first list has no onsort-accept attribute):

<div class="row">
  <div class="col">
    <p>Shop:</p>
    <div class="onsort-copy" sort-name="shop">
      <div class="alert alert-warning">
        Milk
      </div>
      <div class="alert alert-warning">
        Water
      </div>
      <div class="alert alert-warning">
        Limonade
      </div>
    </div>
  </div>
  <div class="col">
    <p>Cart:</p>
    <div class="onsort-move" sort-name="cart" onsort-accept="shop">
      <div class="alert alert-success">
        Milk
      </div>
    </div>
  </div>
</div>

The Sortable library favors the term clone over copy. To respect their naming choices, the onsort-clone attribute is defined as alias of the onsort-copy attribute.

Options

The Sircl extension for Sortable does also support some more advanced features of Sortable:

Disabling sorting

When a list has an onsort class (without action part in its name), a sortable list is created, but its elements are not internally sortable. However, if the list accepts elements from another list, those elements can be dragged to this list, and if another list accepts elements of this list, they can be dragged to the other list(s).

The onsort class can be combined with the onsort-copy class to indicate that items dragged from the list to other lists should be copied.

The onsort class can also be combined with the onsort-submit class to indicate that a form submission should take place when an item of the list is dragged to another list.

Custom Handles

By default, the direct child elements of a sorting list are draggable. To make not the whole element draggable, but only part of it, use the sort-handle attribute on the list parent element with as value a CSS selector matching the element to function as a handle.

An example using a Font Awesome handle icon:

<div class="onsort-move" sort-handle=".handle">
  <div class="alert alert-info">
    <i class="fas fa-grip-lines handle" style="cursor:pointer"></i>
    Monday
  </div>
  <div class="alert alert-info">
    <i class="fas fa-grip-lines handle" style="cursor:pointer"></i>
    Tuesday
  </div>
  <div class="alert alert-info">
    <i class="fas fa-grip-lines handle" style="cursor:pointer"></i>
    Wednesday
  </div>
</div>

Note that relative CSS selectors are not supported.

Filtering

Use the sort-filter attribute on the list parent element with as value a CSS selector selecting elements to ignore (elements that should not be draggable).

Overriding default options

The Sortable component has many more settings to finetune its behavior. All available options are listed here:
https://github.com/SortableJS/Sortable

By default, Sircl initializes options with the following definition:

var sircl_sortable_options_template = {
    animation: 150,
    delay: 300,
    delayOnTouchOnly: true
};

To override settings, add a script after loading the sircl-sortable.js script. For instance, add the following script after loading the sircl-sortable.js script to disable animation during sorting operations:

<script>
  sircl_sortable_options_template.animation = 0;
</script>

 

Loading...