phantom phantom - 6 months ago 39
Javascript Question

jQuery UI Sortable Ignoring items that doesn't match items selector

I've got a special case situation for a table that contains two levels of groupings. I'm dealing with some legacy code that uses a table construct with interleaved rows of class "group" and "member" to show a hierarchy of groups with all of their associated members.

Here is a simplified table:

<table id="my_table">
<thead>
<tr>
<th>column 1</th>
</tr>
</thead>
<tbody>
<tr class="group">
<td>group A</td>
</tr>
<tr class="member">
<td>member A1</td>
</tr>
<tr class="member">
<td>member A2</td>
</tr>
<tr class="group">
<td>group B</td>
</tr>
<tr class="group">
<td>group C</td>
</tr>
<tr class="member">
<td>member C1</td>
</tr>
<tr class="member">
<td>member C2</td>
</tr>
<tr class="member">
<td>member C3</td>
</tr>
<tr class="group">
<td>group D</td>
</tr>
</tbody>
</table>


I'm trying to use jQuery sortable to allow the user to drag and drop the member table rows to the desired position within the table:

$("#my_table tbody").sortable({items: '> .member', forceHelperSize: true });


I am able to drag the "member" rows among other "member" rows to reorder them... That portion is working fine except I can't drag the "member" rows below "group D" (since there are no "member" rows below it).

If I remove the 'items' option, then the "group" rows can also be dragged -- something that I don't want.

I tried to remove the 'items' option and add a 'start' event handler to cancel the sortable if a "group" row was attempted to be moved.

start: function(event, ui) {
if (ui.item.hasClass("group")) {
$(this).sortable('cancel');
}
}


Unfortunately, the 'cancel' action causes:
TypeError "null is not an object" (this.helper.outerWidth)
and a corruption of the table display (the moved "group" row is superimposed with the row below it).

Anyone have another method to suppress the draggability of the "group" rows (while still allowing the "member" rows to be dragged to any row position in the table)?

T J T J
Answer

You can fix the issue by specifying .group as the value of cancel option.

Prevents sorting if you start on elements matching the selector.

If you use items option, the non-matching elements will totally ignored by sortable, but if you use cancel instead, the elements will be considered but will not be draggable.

$("#my_table tbody").sortable({
  cancel: ".group",
  forceHelperSize: true
});
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<table id="my_table">
  <thead>
    <tr>
      <th>column 1</th>
    </tr>
  </thead>
  <tbody>
    <tr class="group">
      <td>group A</td>
    </tr>
    <tr class="member">
      <td>member A1</td>
    </tr>
    <tr class="member">
      <td>member A2</td>
    </tr>
    <tr class="group">
      <td>group B</td>
    </tr>
    <tr class="group">
      <td>group C</td>
    </tr>
    <tr class="member">
      <td>member C1</td>
    </tr>
    <tr class="member">
      <td>member C2</td>
    </tr>
    <tr class="member">
      <td>member C3</td>
    </tr>
    <tr class="group">
      <td>group D</td>
    </tr>
  </tbody>
</table>