How to force jQuery resizable to use percentage?

8.3k views Asked by At

I am trying to use the jQuery resizable to resize my div, I've got it to work pretty good except that after the stop event, jQuery UI would revert my % value back to pixel value.

I've a working fiddle here: http://jsfiddle.net/totszwai/j60h38fy/5/

When you drag the current container for the first time, it would calculate all the value correctly, but after the stop event, jQuery UI would update the % and change it back to pixel... so next time you drag it again, the % is lost.

How do you force jQuery to set the width value to %? I could technically use something like setTimeout, but that would be way too ugly.

And I do not want a solution to manipulate the divs in pixel, because I could technically add n-divs in my setup and that code with % should work with n-divs.

If you take a look at my neighbor div, the % is kept there, only the current got overwritten. I've also tried to play around with ui.element directly as well as setting the ui.size.width to my % but none of that work either.

Update: A workaround is to store the data everytime at the stop event and never check it again at the start, however, this still doesn't solve the issue where stop returns incorrect pixel value. See updated jsFiddle: http://jsfiddle.net/totszwai/j60h38fy/6/

If only jQuery resizable take my % value, everything would've worked as expected.

Solved: Well, I've accepted apaul34208's answer, since i did asked for how to use %. However, to actually solve what I originally wanted to solve, I end up using pixels instead. See the answer that I posted below, if that answer helped you, please upvote that instead.

4

There are 4 answers

2
genspire On BEST ANSWER

I ran into this same issue and the chosen solution doesn't work for me because I need this to generalize to any number of columns. Also codenamezero's answer did not deal with the fact that the original question requires that percentages for widths are used.

For my case using percentages for width is essential because I'm implementing a table editor and the table that is saved must dynamically change size depending on where it is rendered.

So I came up with this solution which works similar to codenamezero's solution but in the stop the changed widths are set to be percentages:
http://jsfiddle.net/genpsire/4mywcm1x/14/

$(document).ready(function () {

    var container = $(".wrapper");
    var numberOfCol = 3;
    $(".test").css('width', 100/numberOfCol +'%');

    var sibTotalWidth;
    $(".test").resizable({
        handles: 'e',
        start: function(event, ui){
            sibTotalWidth = ui.originalSize.width + ui.originalElement.next().outerWidth();
        },
        stop: function(event, ui){     
            var cellPercentWidth=100 * ui.originalElement.outerWidth()/ container.innerWidth();
            ui.originalElement.css('width', cellPercentWidth + '%');  
            var nextCell = ui.originalElement.next();
            var nextPercentWidth=100 * nextCell.outerWidth()/container.innerWidth();
            nextCell.css('width', nextPercentWidth + '%');
        },
        resize: function(event, ui){ 
            ui.originalElement.next().width(sibTotalWidth - ui.size.width); 
        }
    });
});

Please select this solution so others don't spend their morning pulling their hair out trying to generalize apaul34208's solution to the n columns case. (like I did!)

6
codenamezero On

After hammering it for another morning, I finally got the perfect solution. It was actually much simpler than I thought, is just that I was over complicating things.

I was trying to get its dynamic size of the ui.helper and tried to manipulate the neighbor element at the stop. But what I really care is this element's width and its immediate neighbor element's width... so I end up doing the following:

    start: function (event, ui) {
        // just remember the total width of self + neighbor
        this.widthWithNeighbor = 
            ui.originalSize.width + ui.element.next().outerWidth();
    },
    resize: function (event, ui) {
        // then simply subtract it!
        ui.element.next().width(this.widthWithNeighbor - ui.size.width);
    },
    stop: function(event, ui) {
        // clean up, is this needed?
        delete this.widthWithNeighbor;
    }

This solution works for n+1 DIVs sitting side by side. If you flip the width with height, it will also work with vertically stacked DIVs. :)

Cheers!

Working jsFiddle

Note: The ghost and animate option from jQuery-UI is still giving weird issue as before. This is as of jQuery 2.0.2 and jQuery-UI 1.10.3, hopefully they would patch it soon.

0
apaul On

I had to remove ghost and animate and tweak your css a bit, display: flex; seemed to be causing unexpected results, but I think I may have stumbled on a simple solution:

Working Example

$(document).ready(function() {

  $(".test").resizable({
    handles: 'e',
    resize: function() {
      $('.test:first-of-type').css('width', $('.test:first-of-type').outerWidth() * 100 / $(window).innerWidth() + '%');
      $('.test:nth-of-type(2)').css('width', 100 - ($('.test:first-of-type').outerWidth() * 100 / $(window).innerWidth()) + '%');

    }

  });
});
* {
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
html,
body {
  height: 100%;
  width: 100%;
  padding: 0;
  margin: 0;
}
.wrapper {
  height: 100%;
  width: 100%;
}
.test {
  float: left;
  border: 3px solid red;
}
<div class="wrapper">
  <div class="test" style="width: 50%; height: 200px;">current</div>
  <div class="test" style="width: 50%; height: 200px;">neighbor</div>
</div>
1
gus On

I know my answer is not a "good practice" because it requires you to customize a frequently updated library, but it solved my problem: Change the "resize" function inside the jquery-ui.js file to manipulate width as you wish. In my case I needed the resize to ignore width completely so I commented out the "width" change:

resize: function( event, ui ) {
        var that = $( this ).resizable( "instance" ),
            o = that.options,
            os = that.originalSize,
            op = that.originalPosition,
            delta = {
                height: ( that.size.height - os.height ) || 0,
    ----------->//width: ( that.size.width - os.width ) || 0,
                top: ( that.position.top - op.top ) || 0,
                left: ( that.position.left - op.left ) || 0
            };

            $( o.alsoResize ).each( function() {
                var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
                    css = el.parents( ui.originalElement[ 0 ] ).length ?
        ----------------->[ /*"width",*/ "height" ] :
                            [ "width", "height", "top", "left" ];

                $.each( css, function( i, prop ) {
                    var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
                    if ( sum && sum >= 0 ) {
                        style[ prop ] = sum || null;
                    }
                } );

                el.css( style );
            } );
    },