在自定义指令中,如何在生成模板之前执行逻辑?

In a custom directive, how can I perform logic before generating the template?

我想编写一个自定义指令,它接受一个字符串数组,并将其呈现为 table,如下所示:

'string1'  | 'string2'  | 'string3'  | 'string4'
'string5'  | 'string6'  | 'string7'  | 'string8'
'string9'  | 'string10' | 'string11' | 'string12'

应该这样使用:

<div class="my-directive" values="values" rowsize="4"></div>

我认为实现此目标的适当策略是首先将 values 拆分为大小为 rowsize 的数组。然后,使用内部 ng-repeat 渲染 ng-repeat。所以指令的输出 DOM 看起来像这样:

<table>
    <tr ng-repeat="part in parts">
        <td ng-repeat="value in part">
            {{value}}
        </td>
    </tr>
</table>

这意味着在指令中我需要首先做一些逻辑(将数组拆分成更小的数组),然后使用ng-repeat 如上所示。

该指令也可以使用手动 DOM 操作来编写,但我想以 'the Angular' 的方式做事 :)

所以,问题是:在自定义指令中,如何先做一些逻辑(通常在link函数中完成),然后生成一个模板(通常放在template 属性)?

这应该可以解决问题:http://plnkr.co/edit/UYMQtMuZeJRcSQynHUGW?p=info

基本上,我们需要动态创建包含项目数组的行对象。如果我们没有达到允许的最大列数,我们只想添加到这个项目数组,正如通过 maxColumns:

传递到指令中所指定的那样

正如您将通过 plunker 看到的那样,您可以修改 HTML 中的 max-columns 属性,指令应该适当地绘制:

app.controller('MainCtrl', function($scope) {
  $scope.values = [
    'string1','string2','string3','string4','string5','string6',
    'string7','string8','string9','string10','string11','string12'
  ];
});

app.directive('myTable', function() {

  var templateHtml = 
      '<table border="1">' +
          '<tr ng-repeat="row in rows">' + 
              '<td ng-repeat="item in row.items">{{item}}</td>' +
          '</tr>' + 
      '</table>';

  return {
    restrict: 'E',
    template: templateHtml,
    scope: {
      values: '=',
      maxColumns: '@'
    },
    link: function(scope, element, attrs) {

        scope.rows = [];
        scope.rows.push(_getNewRow())

        function _getNewRow() {
          return { items: [] };
        }

        _.each(scope.values, function(value) {
            currentRow = _.last(scope.rows);
            if (currentRow.items.length < scope.maxColumns) {
               currentRow.items.push(value);
            } else {
               currentRow = _getNewRow();
               currentRow.items.push(value);
               scope.rows.push(currentRow);
            }
        });

    }
  }
});