Matt Grey
Matt Grey

Reputation: 33

Drag resizing bootstrap columns jQuery UI

I'm trying to get columns in a bootstrap row to snap-resize incrementally to their respective column sizes by dragging either way. They must always add up to 12 columns.

See an example of what I'm trying to achieve

The closest example of what I need is here: http://jsfiddle.net/onigetoc/ag4mgpbs/ however the columns around them do not resize larger or smaller depending on the column next to them.

I have looked at using [gridstack.js to achieve this, but I can't get the logic of adding or subtracting columns correctly with basic jQuery/jQuery UI.

The code I've written I'm sure is going in the wrong direction, I can't work out why the columns don't add up when I expect them to, it might be something to do with the events I'm using.

    var oldColNum = 0;
    var nextColFraction = 0;

    $('.column').resizable({
        handles: 'e',
        containment: 'parent',
        start: function (e, ui) {
            var nextCol = $(this).nextAll('.column').get(0);
            nextColFraction = $(nextCol).data('fraction');
            $(this).closest('.row').find('.column').css("width", '');
        },
        resize: function (e, ui) {

            // console.clear();

            /**
             * The Column currently being resized
             */
            var thisCol = ui.element;
            oldColNum = thisCol.data('fraction');

            /**
             * The parenting row
             */
            var parentRow = thisCol.closest('.row');

            /**
             * The Other Columns
             */
            var nextCol = thisCol.nextAll('.column').get(0);
            var otherCols = parentRow.find('.column').not(thisCol);
            var otherColFractions = [];
            otherCols.each(function () {
                otherColFractions.push($(this).data('fraction'));
            });
            var totalOtherFractions = otherColFractions.reduce(function(a, b) { return a + b }, 0);

            /**
             * Work out the percentage width it currently is
             */
            var cellPercentWidth = (100 * thisCol.outerWidth() / parentRow.outerWidth());

            /**
             * Change the class to the one that best suits the current size
             */
            var colNum = getClosest(gridSystem, cellPercentWidth);

            console.log(colNum, ui.originalElement.data('fraction'));

            if (colNum < ui.originalElement.data('fraction')) {
                nextColFraction++;
                $(nextCol).removeClass(bsClass)
                    .addClass('col-md-' + nextColFraction)
                    .attr('data-fraction', nextColFraction);
            }

            if (colNum > ui.originalElement.data('fraction')) {
                nextColFraction--;
                $(nextCol).removeClass(bsClass)
                    .addClass('col-md-' + nextColFraction)
                    .attr('data-fraction', nextColFraction);
            }

            thisCol.removeClass(bsClass)
                    .addClass('col-md-' + colNum)
                    .attr('data-fraction', colNum);

            thisCol.css("width", '');
        }
    });
});

// Bootstrap grid system array
var gridSystem = [
    {grid: 8.33333333, col: 1},
    {grid: 16.66666667, col: 2},
    {grid: 25, col: 3},
    {grid: 33.33333333, col: 4},
    {grid: 41.66666667, col: 5},
    {grid: 50, col: 6},
    {grid: 58.33333333, col: 7},
    {grid: 66.66666667, col: 8},
    {grid: 75, col: 9},
    {grid: 83.33333333, col: 10},
    {grid: 91.66666667, col: 11},
    {grid: 100, col: 12}
];

// find the closest number from Bootstrap grid
function getClosest(arr, value) {
    var closest, mindiff = null;

    for (var i = 0; i < arr.length; ++i) {
        var diff = Math.abs(arr[i].grid - value);

        if (mindiff === null || diff < mindiff) {
            // first value or trend decreasing
            closest = i;
            mindiff = diff;
        } else {
            return arr[closest]['col']; // col number
        }
    }
    return null;
}

Any help would be greatly appreciated.

Upvotes: 3

Views: 2251

Answers (2)

Anima-t3d
Anima-t3d

Reputation: 3565

NOTE: This is more of a clarification than an answer, but too much code to put in a comment.

The getClosest function does not cover the case where an element is more than 11 cols. I changed the following part:

function getClosest(arr, value) {
  var closest, mindiff = null;

  for (var i = 0; i < arr.length; ++i) {
    var diff = Math.abs(arr[i].grid - value);

    if (mindiff === null || diff < mindiff) {
      // first value or trend decreasing
      closest = i;
      mindiff = diff;
    } else {
      // trend will increase from this point onwards
      //return arr[closest]; //object
      return arr[closest]['col']; // col number
      //return arr[closest]['grid']; // col percentage

    }
  }
  return null;
}

to:

function getClosest(arr, value) {
  let closest, mindiff = null;

  for (let i = 0; i < arr.length; ++i) {
    let diff = Math.abs(arr[i].grid - value);

    if (i === arr.length - 1 && value >= 95) {
      // No other matches, cap at last size
      return arr[i]['col']; // col number
    } else if (mindiff === null || diff < mindiff) {
      // First value or trend decreasing
      closest = i;
      mindiff = diff;
        } else {
      return arr[closest]['col']; // col number
    }
  }
    // Invalid
  return null;
}

Upvotes: 0

Coding Friend
Coding Friend

Reputation: 73

You would find the next column after it that has the grid class and remove one from it.

$(function() {

  var bsClass = "col-sm-1 col-sm-2 col-sm-3 col-sm-4 col-sm-5 col-sm-6 col-sm-7 col-sm-8 col-sm-9 col-sm-10 col-sm-11 col-sm-12";

  $(document).ready(function() {
    $('.mb-grid-item').resizable({
        handles: "e",
        resize: function(e, ui) {
          console.log('resizable');
          var thiscol = $(this);

          var currentNumberBefore = parseInt(thiscol.attr('class').match(/col-sm-(\d+)/)[1]);

          var container = thiscol.parent();

          var cellPercentWidth = 100 * ui.originalElement.outerWidth() / container.innerWidth();

          // ui.originalElement.css('width', cellPercentWidth + '%');

          var newColNum = getClosest(gridsystem, cellPercentWidth);
          var thiscol = $(this);


          thiscol.css("width", '');
          //thiscol.removeAttr("style");
          thiscol.find(".showClass").text('col-sm-' + newColNum);
          //alert(cellPercentWidth);

          var currentTopPosition = thiscol.position().top

          var nextColumn = thiscol.next('.mb-grid-item');

          var nextTopPosition = nextColumn.position().top;

          if(currentNumberBefore !== newColNum && nextColumn && nextTopPosition === currentTopPosition) {
            try {
              var nextNumber = nextColumn.attr('class').match(/col-sm-(\d+)/)[1];
              if(nextNumber) {
                nextNumber = parseInt(nextNumber);
                if((nextNumber+1) > 0) {
                  nextColumn.removeClass(bsClass);
                  var nextColumnNumber
                  if(currentNumberBefore > newColNum) {
                    nextColumnNumber = nextNumber+1;
                  } else {
                    if(nextNumber-1 > 0) {
                      nextColumnNumber = nextNumber-1;
                    } else {
                      nextColumnNumber = nextNumber;
                    }

                  }
                  var nextClass = 'col-sm-' + nextColumnNumber.toString();
                  nextColumn.find(".showClass").text(nextClass);
                  nextColumn.addClass(nextClass);
                }
              }
            } catch(err) {
              console.log('err', err);
            }
          }

          thiscol.removeClass(bsClass).addClass('col-sm-' + newColNum);
        }
      }
    );
  }); //ready end
});

/***********************/

// Bootstrap grid system array
var gridsystem = [{
  grid: 8.33333333,
  col: 1
}, {
  grid: 16.66666667,
  col: 2
}, {
  grid: 25,
  col: 3
}, {
  grid: 33.33333333,
  col: 4
}, {
  grid: 41.66666667,
  col: 5
}, {
  grid: 50,
  col: 6
}, {
  grid: 58.33333333,
  col: 7
}, {
  grid: 66.66666667,
  col: 8
}, {
  grid: 75,
  col: 9
}, {
  grid: 83.33333333,
  col: 10
}, {
  grid: 100,
  col: 11
}, {
  grid: 91.66666667,
  col: 12
}, {
  grid: 10000,
  col: 10000
}];

// find the closest number from Bootstrap grid
function getClosest(arr, value) {
  var closest, mindiff = null;

  for (var i = 0; i < arr.length; ++i) {
    var diff = Math.abs(arr[i].grid - value);

    if (mindiff === null || diff < mindiff) {
      // first value or trend decreasing
      closest = i;
      mindiff = diff;
    } else {
      // trend will increase from this point onwards
      //return arr[closest]; //object
      return arr[closest]['col']; // col number
      //return arr[closest]['grid']; // col percentage

    }
  }
  return null;
}
```

Upvotes: 1

Related Questions