Search code examples
javascriptjqueryjquery-uijquery-ui-resizable

Keep resizable children within parent


I'd like to keep the resizable elements within the parent element.

What I did:
I gave already the minHeight : property and wile resizing I'm constraining the new height using Math.max to keep it at 30px height

Expected:
All resizable children elements should always be visible and minimally 30px in height.

Issue:
Somehow if you resize the lower elements, at some point vertical the big scrollbar appear and the resizable goes out of containment:"parent" (why?).
To recap - the page's vertical scrollbar should never appear an one should be always able to get to the "c" element.

$(".resiz").not(":last").resizable({
  handles: 's',
  minHeight : 30,
  containment: "parent",        /* seems not to work?! */
  start:function(e,ui) {
    this.other= $(this).next() || $(this).prev();
    this.startingHeight = this.other.height();
  },
  resize:function(e,ui) {
    var diffH = ui.size.height - ui.originalSize.height;
    this.other.height( Math.max(30, this.startingHeight - diffH) );
  }
});
*{box-sizing:border-box; margin:0;}
html, body{height:100%;}
#panel{
  position:absolute;
  height:100%;
  width:200px;
}
.resiz{
  height:33vh;
  width:100%;
  background:#eee;
}
.ui-resizable-s{
  height:3px;
  background:#08f;
}
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>

<div id="panel">
  <div class='resiz'>a</div>
  <div class='resiz'>b</div>
  <div class='resiz'>c</div>
</div>

Edit: Seems related but the answer is not what I expected...


Solution

  • You are changing the height of the last div but never the actual div being resized. So the containment grows with the last div being pushed and since the containment is applied on the div being resized, it's never applied.

    So to solve your problem I think you need to resize the last div until it's a maximum height, and when it's the case prevent anymore resizing. You could do it like this, although it seems there could be a more efficient way. Still it'll give you some ideas:

    $(".resiz").not(":last").resizable({
      handles: 's',
      minHeight: 30,
      containment: "parent",
      /* seems not to work?! */
      start: function(e, ui) {
        this.maxHeight = undefined;
        this.other = $(this).next();
        this.startingHeight = this.other.height();
      },
      resize: function(e, ui) {
        var diffH = ui.size.height - ui.originalSize.height;
        
        //when next div is at max height, you prevent resizing of current div
        if (Math.max(30, this.startingHeight - diffH) == 30) {
          this.maxHeight = this.maxHeight || (this.prevHeight);
          ui.size.height = this.maxHeight;
        //until it's at max div you resize next div  
        } else {
          this.other.height(this.startingHeight - diffH);
          this.prevHeight = ui.size.height;
        }
      }
    
    });
    * {
      box-sizing: border-box;
      margin: 0;
    }
    html,
    body {
      height: 100%;
    }
    #panel {
      position: absolute;
      height: 100%;
      width: 200px;
    }
    .resiz {
      height: 33vh;
      width: 100%;
      background: #eee;
    }
    .ui-resizable-s {
      height: 3px;
      background: #08f;
    }
    <link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
    
    <div id="panel">
      <div class='resiz'>a</div>
      <div class='resiz'>b</div>
      <div class='resiz'>c</div>
    </div>