Search code examples
jqueryjquery-ui-sortable

jquery sortable remove next row before sorting


I have one table containing parent and child as below. parent are sortable. When I try to sort any parent, I've to remove it's next child and insert it after it's new position.

<table>
    <tr class="parent"><td>Parent1</td></tr>
    <tr class="child nosort"><td>Child1</td></tr>
    <tr class="parent"><td>Parent2</td></tr>
    <tr class="child nosort"><td>Child2</td></tr>
    <tr class="parent"><td>Parent3</td></tr>
    <tr class="child nosort"><td>Child3</td></tr>
</table>

So if I move Parent1 after Parent2, it will look:

<table>       
    <tr class="parent"><td>Parent2</td></tr>
    <tr class="child nosort"><td>Child2</td></tr>
    <tr class="parent"><td>Parent1</td></tr>
    <tr class="child nosort"><td>Child1</td></tr>
    <tr class="parent"><td>Parent3</td></tr>
    <tr class="child nosort"><td>Child3</td></tr>
</table>

I've done with the insertion of child after sortupdate but not able to figure out how to remove child row before sort. Below if code written on start.

$('table').sortable({
    items: 'tr:not(.nosort)',
    start: function( event, ui ) {
        // Removal code of child before sort
        var objChild = ui.item.next();
        if( objChild.hasClass('child') ) {
            objChild.remove();
        }
    },
    update: function( event, ui ) {
    //  insertion code of child
    }
});

Solution

  • To answer exactly what you asked:

    • Store the next elements into data-* attribute of each .parent
    • On sortable start event use Use jQuery's .detach() to store the child element(s) into data.
    • On sortable stop event use .after() ti insert the previously detached elements

    $('.parent').each(function(i, e) {
       $(this).data('$next', $(this).nextUntil('.parent'));
    });
    
    $('table').sortable({
      items: 'tr:not(.nosort)',
      start: function( ev, ui ) {
        $next = $(ui.item.data('$next')).detach();    
      },
      stop: function(event, ui) {
        ui.item.after($next);
      }
    });
    <table>
      <tr class="parent"><td>1 Parent</td></tr>
      <tr class="child nosort"><td>1 Child</td></tr>
      <tr class="parent"><td>2 Parent</td></tr>
      <tr class="child nosort"><td>2 Child</td></tr>
      <tr class="parent"><td>3 Parent</td></tr>
      <tr class="child nosort"><td>3 Child</td></tr>
    </table>
    
    <script src="https://code.jquery.com/jquery-3.1.0.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

    but as you know, you could end up also having P2 P1 C1 C2 ... but that was not your question. Otherwise, to tackle with that problem the best would be to go back to the whiteboard, and simply place two <div>s inside a <td>