Angular JS resizable div directive

2020-01-26 18:49发布

问题:

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?

回答1:

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

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);
        }
    };
});


回答2:

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">


回答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



回答4:

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.