简体   繁体   中英

Manipulate DOM from directive after data is bound

My goal is to create a directive that arranges a set of varied height divs into a pattern that eliminates whitespace between them. Like how Pinterest tessellates divs into a mosaic:

Pinterest截图

My approach to this was:

  1. Create a directive that will wrap a set of divs to tessellate.

     <tessellate columns="6"> <div ng-repeat="item in items" class="thumbnail"> {{item.name}} </div> </tessellate> 
  2. Use a directive template to set up the columns first. (tessellateTemplate.html)

     <div class="container"> <div class="row"> <div class="col-sm-{{12/columns}}" ng-repeat="i in numberToArray(columns) track by $index"></div> </div> </div> 
  3. Use the directive to grab the divs after the data has been bound to them and, one-by-one, add them to the column with the shortest height.

     app.directive('tessellate', function () { return { restrict: 'E', scope: { columns: '=' }, controller: ['$scope', function ($scope) { // Ensure number of columns is divisible by 12. if (isNaN($scope.columns) || 12 % $scope.columns != 0) { $scope.columns = 6; } $scope.numberToArray = function (num) { return new Array(num); }; }], // Get child divs and add to template here. // Should I use compile or link?? templateUrl: "/app/directives/templates/tessellateTemplate.html" }; }); 

Seems simple enough, right? The problem I keep running into is that I can't figure out how to get the divs after data has been bound to them. This is important because the real height of the divs is needed to decide which column it should go in.

Is there a way to manipulate the DOM in the directive after data is bound?

To answer my own question, the only way I could figure this out was to use $timeout. I'm not a fan of it, but it works. If anyone has a better way, please post an answer. :)

I modified my directive template (tessellateTemplate.html) to transclude the divs:

<div>
    <div class="container">
        <div class="row">
            <div class="col-sm-{{12/columns}}" ng-repeat="i in numberToArray(columns) track by $index"></div>
        </div>
    </div>
    <div ng-transclude></div>
</div>

Then I modified my directive to have transclude: true and also do the tessellating in a $timeout (please don't laugh at my chained method calls, it's been a while since I've had to use JQuery :P):

app.directive('tessellate', function () {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        scope: {
            columns: '='
        },
        controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
            // Ensure number of columns is divisible by 12.
            if (isNaN($scope.columns) || 12 % $scope.columns != 0) {
                $scope.columns = 6;
            }

            $scope.numberToArray = function (num) {
                return new Array(num);
            };

            $scope.getShortestColumn = function () {
                var cols = $element.children().first().children().first().children();
                var shortCol = null;
                angular.forEach(cols, function (col) {
                    col = angular.element(col);
                    if (shortCol == null || col.height() < shortCol.height()) {
                        shortCol = col;
                    }
                });
                return shortCol;
            };

            $timeout(function () {
                var divs = $element.children().first().next().children();
                for (var i = 0; i < divs.length; i++) {
                    $scope.getShortestColumn().append(divs[i]);
                }
            }, 0);
        }],
        templateUrl: "/app/directives/templates/tessellateTemplate.html"
    };
});

Usage remains the same:

<tessellate columns="6">
    <div ng-repeat="item in items">
        {{item.name}}
    </div>
</tessellate>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM