12

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.

Community
  • 1
  • 1
codenamezero
  • 2,724
  • 29
  • 64

4 Answers4

10

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!)

genspire
  • 136
  • 6
  • 1
    The container doesn't have to be a table so this will work with divs. If you are using to display tabular data, you are OK. I agree that
    should not be used to format a page. In my case we are displaying tabular data.
    – genspire Jan 27 '15 at 20:48
  • Thanks, good solution! It fails the shift-drag test (for aspect ratio scaling), but so do all the other answers that use `.resizable()` (because the height changes when resizing while holding shift) However, this is easy to fix by doing this in the `resizable` and `stop` events: `$(this).css('height','')`. I forked your fiddle and added several fixes and improvements here: http://jsfiddle.net/8auwgazu/ – nothingisnecessary Mar 09 '16 at 17:40
2

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>
apaul
  • 16,092
  • 8
  • 47
  • 82
2

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.

codenamezero
  • 2,724
  • 29
  • 64
  • I thought you were trying to get the resizable elements working with %, did I misunderstand the question? Your answer seems to return widths in px in both Firefox and Chrome. – apaul Dec 02 '14 at 21:03
  • Hum... yeah you are right. Originally I wanted to get it to work with % since I couldn't find a way to properly adjust the DIVs. I guess I could just accept your answer, if you could revise it to work with n+1 DIVs? – codenamezero Dec 03 '14 at 13:58
  • I'll take another crack at it later today – apaul Dec 03 '14 at 14:02
  • 2
    I'm thinking something along these lines should do it, but it still needs a lot of work: http://jsfiddle.net/apaul34208/bqr7eL1c/5/ – apaul Dec 04 '14 at 16:37
  • hehe... it won't work, because you are still assuming window's width, so it won't work if you have nested elements. in my example that uses pixels, i was able to include my `component` within another `component`. yeah it is extremely tricky to use % to archive what I wanted to archive and probably not worth the time since using pixel seems to be easier and more suitable. however, i think it could still be done, but we will need to save/take care of all the % everywhere and compute them using the stored %... – codenamezero Dec 04 '14 at 19:34
  • I will accept your answer for the effort of helping me out. :) – codenamezero Dec 04 '14 at 19:35
1

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 );
            } );
    },
gus
  • 117
  • 1
  • 6
  • 1
    Yeah it would work but I will tell you from my experience that hacking 3rd party libraries is a pain in the butt to maintain and upgrade for the future. You may also introduce obscure bugs that affect other loosely related code elsewhere making it a nightmare to track and patch/fix/hack. – codenamezero Aug 10 '16 at 12:38