Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying containment to jQuery UI Sortable table prevents moving tall rows to the last position

I have a HTML table, for which I am trying to use the jQuery UI Sortable Widget to enable re-ordering of the rows. I have set the sortable axis: 'y', am using a helper function to preserve the widths of the rows when they are being dragged, and have set the containment to be the parent table:

jQuery(function($) {
    $("#rows").sortable({
        handle: ".handle",
        axis: "y",
        containment: "#main-table",
        helper: function(e, row) {
            // From http://www.paulund.co.uk/fixed-width-sortable-tables. 
            // Sets the width of each cell to be its original width.
            // This prevents the row collapsing into a narrower stub when being dragged.
            row.children().each(function() {
                $(this).width($(this).width());
            });
            return row;
        }
    });
});

However, when there are rows which have multiple line height, the containment does not behave as expected: when dragging the larger row, the height of the table reduces, and the containment shrinks even more such that the large row cannot be moved to the bottom of the table. The other rows work fine.

A JSFiddle showing this behaviour can be found here: https://jsfiddle.net/AndrewBennet/rc5pnazc/3/

Is this known/expected behaviour? Is there any workaround?

like image 794
Andrew Bennet Avatar asked Mar 13 '23 15:03

Andrew Bennet


1 Answers

The way containment is set is that when the drag starts, coordinates of the element are calculated and pushed to an array which is then used to see if a drag should occur on mouse move. What happens in your case is that this calculation is made after the row is removed from the table, so the containment values are not correct.

One thing you can do is adjust these values on start event so that they match the state of the table before removing the rows from the calculations. You can access them through instance method of sortable.

If you want to be even more precise, you can adjust top coordinate of this containment property as well so that it takes in consideration the click offset.

Like this for example:

jQuery(function($) {
  $("#rows").sortable({
    handle: ".handle",
    axis: "y",
    containment: '#main-table',
    start: function(e, ui) {
      // get the instance of the sortable.
      // instance method is new to jquery ui 1.11, for previous versions
      // you can use $(this).data()['ui-sortable'];
      var sort = $(this).sortable('instance');

      // this makes the placeholder fit with the row that's being dragged
      ui.placeholder.height(ui.helper.height());

      // containment property of the sortable instance is not the same
      // as the containment option. The property is calculated
      // from the option. You need to adjust bottom coordinates
      // to take into account the row you just removed from it and the click offset.
      sort.containment[3] += ui.helper.height() * 1.5 - sort.offset.click.top;

      // Since your handle is centered, and pointer coordinates are used
      // for sortable, but top coordinates are used for containment
      // you can have issues with top row. Adjusting with the click offset
      // will resolve the issue.
      sort.containment[1] -= sort.offset.click.top;
    },

    helper: function(e, row) {
      // From http://www.paulund.co.uk/fixed-width-sortable-tables. 
      // Sets the width of each cell to be its original width.
      // This reverts the default behaviour of the row collapsing into a narrower stub when being dragged.
      row.children().each(function() {
        $(this).width($(this).width());

      });
      return row;
    }
  });
});

https://jsfiddle.net/f1nexjmz/4/

like image 194
Julien Grégoire Avatar answered Mar 15 '23 03:03

Julien Grégoire