1

我的意图是创建一个指令,可以将其子元素重新排列(而不是重新排序)到 Bootstrap CSS 网格中,但是我在访问子元素时遇到了很多困难。

我尝试了很多不同的东西,并研究了 Compile vs Link vs Controller 指令选项。我想我可能必须在我的指令中将“编译”更改为“链接”才能使其正常工作,但我不确定如何做到这一点。

在 GitHub 上有一个 AngularJS 指令,它采用参数数组或对象来呈现简单或复杂的网格。

在下面的示例中,您可以看到layoutOptions.data = [3, 4]这意味着网格将在第一行有 3 个单元格,在第二行有 4 个单元格。这运作良好。

第二步是我想将一些 div 渲染为指令的子元素,并且指令将在创建网格时将它们放置在网格的单元格中。由layoutOptions.content = ['apple', 'orange', 'pear', 'banana', 'lime', 'lemon', 'grape']_

HTML 输入

<div ng-app="blerg">
  <div ng-controller="DemoCtrl">
    <div class="container" hr-layout="layoutOptions">
      <div ng-transclude ng-repeat="fruit in layoutOptions.content">{{fruit}}</div>
    </div>
  </div>
</div>

期望(非实际)输出

实际输出如下,但不包括带有水果名称的内部 DIV

<div class="container hr-layout" hr-layout="layoutOptions">
  <div class="row">
    <div class="col-md-4"><!-- from ng-repeat --><div>apple</div></div>
    <div class="col-md-4"><!-- from ng-repeat --><div>orange</div></div>
    <div class="col-md-4"><!-- from ng-repeat --><div>pear</div></div>
  </div>
  <div class="row">
    <div class="col-md-3"><!-- from ng-repeat --><div>banana</div></div>
    <div class="col-md-3"><!-- from ng-repeat --><div>lime</div></div>
    <div class="col-md-3"><!-- from ng-repeat --><div>lemon</div></div>
    <div class="col-md-3"><!-- from ng-repeat --><div>grape</div></div>
  </div>
</div>

还有一个在这里使用它的 jsFiddle:http: //jsfiddle.net/harryhobbes/jJDZv/show/

代码

angular.module('blerg', [])
  .controller('DemoCtrl', function($scope, $timeout) {
    $scope.layoutOptions = {
      data: [3, 4],
      content: ['apple', 'orange', 'pear', 'banana', 'lime', 'lemon', 'grape']
    };
  })
  .directive("hrLayout", [
    "$compile", "$q", "$parse", "$http", function ($compile, $q, $parse, $http) {
      return {
        restrict: "A",
        transclude: true,
        compile: function(scope, element, attrs) {
          //var content = element.children();
          return function(scope, element, attrs) {
            var contentCount = 0;
            var renderTemplate = function(value, content) {
              if (typeof content === 'undefined' || content.length <= contentCount)
                var cellContent = 'Test content(col-'+value+')';
              else if (Object.prototype.toString.call(content) === '[object Array]')
                var cellContent = content[contentCount];
              else
                var cellContent = content;

              contentCount++;
              return '<div class="col-md-'+value+'">'+cellContent+'</div>';
            };

            var renderLayout = function(values, content) {
              var renderedHTML = '';
              var rowCnt = 0;
              var subWidth = 0;

              angular.forEach(values, function(value) {
                renderedHTML += '<div class="row">';
                if(Object.prototype.toString.call(value) === '[object Array]') {
                  angular.forEach(value, function(subvalue) {
                    if(typeof subvalue === 'object') {
                      renderedHTML += renderTemplate(
                        subvalue.w.substring(4), renderLayout(subvalue.d)
                      );
                    } else {
                      renderedHTML += renderTemplate(subvalue.substring(4));
                    }
                  });
                } else {
                  if(value > 12) {
                    value = 12;
                  } else if (value <= 0) {
                    value = 1;
                  }
                  subWidth = Math.floor(12 / value);
                  for (var i=0; i< value-1; i++) {
                    renderedHTML += renderTemplate(subWidth);
                  }
                  renderedHTML += renderTemplate((12-subWidth*(value-1)));
                }
                renderedHTML += '</div>';
                rowCnt++;
              });
              return renderedHTML;
            };

            scope.$watch(attrs.hrLayout, function(value) {
              element.html(renderLayout(value.data));
            });
            element.addClass("hr-layout");
          };
        }
    };
  }]);
4

2 回答 2

0

你的方法看起来太复杂了。也许你应该使用ngRepeat指令http://docs.angularjs.org/api/ng.directive:ngRepeatorderBy过滤器http://docs.angularjs.org/api/ng.filter:orderBy来更新元素的html hrLayout的更新时间?

于 2013-11-04T11:01:36.620 回答
0

这可能会有所帮助 - http://jsfiddle.net/PwNZ5/1/

App.directive('hrLayout', function($compile) {
    return {
        restrict: 'A',

        // allows transclusion
        transclude: true,

        // transcludes the content of an element on which hr-layout was placed
        template: '<div ng-transclude></div>',

        compile: function(tElement, tAttrs, transcludeFn) {
            return function (scope, el, tAttrs) {
                var data = scope.$eval(tAttrs.hrLayout),
                    dom = '';

                transcludeFn(scope, function cloneConnectFn(cElement) {
                    // hide the transcluded content
                    tElement.children('div[ng-transclude]').hide();

                    // http://ejohn.org/blog/how-javascript-timers-work/‎
                    window.setTimeout(function() {
                        for(var row = 0; row < data.data.length; row++) {
                            dom+= '<div class="row">';
                            for(var col = 0; col < data.data[row]; col++) {
                                dom+= '<div class="col-md-' + data.data[row] + '">' + tElement.children('div[ng-transclude]').children(':eq(' + ( row + col ) + ')').html() + '</div>';
                            }
                            dom+= '</div>';
                        }

                        tElement.after(dom);
                    }, 0);
                });
            };
        }
    };
});
于 2013-11-09T09:21:03.163 回答