47

My site will have multiple sections, each of which I intend to be resizable. To accomplish this I've made a "resizable" directive, e.g.:

<div class="workspace" resize="full" ng-style="resizeStyle()"> <div class="leftcol" resize="left" ng-style="resizeStyle()"> 

With a directive that looks something like:

lwpApp.directive('resize', function ($window) { return { scope: {}, link: function (scope, element, attrs) { scope.getWinDim = function () { return { 'height': window.height(), 'width': window.width() }; }; // Get window dimensions when they change and return new element dimensions // based on attribute scope.$watch(scope.getWinDim, function (newValue, oldValue) { scope.resizeStyle = function () { switch (attrs.resize) { case 'full': return { 'height': newValue.height, 'width': (newValue.width - dashboardwidth) }; case 'left': return { 'height': newValue.height, 'width': (newValue.width - dashboardwidth - rightcolwidth) }; etc... }; }, true); //apply size change on window resize window.bind('resize', function () { scope.$apply(scope.resizeStyle); }); } }; }); 

As you can see, this only resizes each div on window resize, and each directive has an isolate scope. This works fine for what it's built for, but ultimately I would like to make a subset of the divs resizable via a draggable bar. For instance

div1 div2 ---------------- | || | | || | | || | | || | ---------------- draggable bar in middle 

On the the draggable bar's movement (in the horizontal direction), I would need to access both div1, div2's width presumably via the scope of a parent controller(?). My questions are:

  1. Is this the "correct" way to go about making resizable divs in angular? In particular, when the size of one div affects another?

  2. I personally feel like the answer to (1) is "No, I am not doing it correctly because I cannot communicate between directives when each has an isolate scope." If this is true, how can I account for both window and draggable resizing between divs?

3
  • I don't have a clear answer for you but I would check out things like the BootstrapUI Accordion or similar where there is a main directive that uses some other directives and "communicates" the appropriate information between them to open and close the appropriate sections. I believe you'll be using require property of the directive definition object, see the long version here docs.angularjs.org/guide/directive Commented Aug 21, 2013 at 22:21
  • Thanks! I think you might be right with the require. That will give me access to another controller... Commented Aug 22, 2013 at 15:25
  • I've just been trying this out. I had a go with jQuery-Splitter as jayflo suggested but I struggled with this and also got the impression the code is unsupported. I've tried again using JQueryUI resizable and that is working fine. Next step is to integrate with Angular, and I'm going to use AngularJS-JQueryUI Commented Feb 17, 2014 at 23:31

4 Answers 4

99

This question is old, but for anybody looking for a solution, I built a simple directive to handle this, for vertical and horizontal resizers.

Take a look at the Plunker

enter image description here

angular.module('mc.resizer', []).directive('resizer', function($document) { return function($scope, $element, $attrs) { $element.on('mousedown', function(event) { event.preventDefault(); $document.on('mousemove', mousemove); $document.on('mouseup', mouseup); }); function mousemove(event) { if ($attrs.resizer == 'vertical') { // Handle vertical resizer var x = event.pageX; if ($attrs.resizerMax && x > $attrs.resizerMax) { x = parseInt($attrs.resizerMax); } $element.css({ left: x + 'px' }); $($attrs.resizerLeft).css({ width: x + 'px' }); $($attrs.resizerRight).css({ left: (x + parseInt($attrs.resizerWidth)) + 'px' }); } else { // Handle horizontal resizer var y = window.innerHeight - event.pageY; $element.css({ bottom: y + 'px' }); $($attrs.resizerTop).css({ bottom: (y + parseInt($attrs.resizerHeight)) + 'px' }); $($attrs.resizerBottom).css({ height: y + 'px' }); } } function mouseup() { $document.unbind('mousemove', mousemove); $document.unbind('mouseup', mouseup); } }; }); 
Sign up to request clarification or add additional context in comments.

1 Comment

Are there any versions for Angular >= 2
22

I know I'm a bit late to the party, but I found this and needed my own solution. If you're looking for a directive that works with flexbox, and doesn't use jquery. I threw one together here:

http://codepen.io/Reklino/full/raRaXq/

Just declare which directions you want the element to be resizable from, and whether or not you're using flexbox (defaults to false).

<section resizable r-directions="['right', 'bottom']" r-flex="true"> 

1 Comment

Very helpful! Here's a super simple plunker (using angular-resizable) for those who want to get it working real quick. Just look at index.html plnkr.co/edit/ww3axpDkBTJuGX1gfIlA?p=preview
3

For the needs of my project i added support of minimum values, so that panels can keep some width or height - (here is the gist) - Github

Also, i created Github repo, where i added support for panels being located right of main page axis and support of minimum/maximum values. It's in example stage now, but i'm willing to turn it into a full-weight Angular directive

2 Comments

handling % value for min/max might be another good addition to this.
@Mutant sure, i'll look into this, thanks for the proposal
0

This does not completely answer the question, but changing scope: true solved the isolate scope problem. In particular, in my html I have:

<div ng-controller="WorkspaceCtrl"> <div class="workspace" resize="full" ng-style="resizeStyle()"> <div class="leftcol" resize="left" ng-style="resizeStyle()"> <ul class="filelist"> <li ng-repeat="file in files" id={{file.id}} ng-bind=file.name></li> </ul> <div contenteditable="true" ng-model="content" resize="editor" ng-style="resizeStyle()"> Talk to me </div> </div> </div> 

and ng-repeat="file in files" still has access to the array $scope.files defined in the controller WorkspaceCtrl. So scope: {} cuts off the scope of the directive from the scope of the parent controller, whereas scope: true simply creates a new scope for each instance of the directive AND each instance of the directive, along with its children, retains access to the parent scope.

I have not yet implemented the draggable bar which resizes these divs, but will report back when I do so.

3 Comments

Any luck implementing this yet?
No, sorry. It's simple to make divs resize on window resize. I've become distracted with other things and haven't tried to make the divs themselves resizable. However, I'm sure that it would be accomplished by using draggable "shims" which lie inbetween the divs. Also, make sure you don't isolate the scope for any directives you wish to resize this way.
Since I asked this yesterday, I found a fairly decent solution to the problem. Check out this forked version of jQuery Splitter: github.com/e1ven/jQuery-Splitter. To get it to work with jQuery 1.9+, you need to reinstate jQuery.browser (I use this code). Hook that up with a linking function and you should be good to go.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.