角度表达指令设计

时间:2015-06-15 12:38:02

标签: angularjs angularjs-directive

我正在开发一个AngularJS Data Table指令(仍为WIP)的开源项目。当您查看Angular GridUI Grid等组件时,它们都会在父控制器的对象中描述它们的列和属性,如:

$scope.gridOptions = {
  enableSorting: true,
  enableCellEditOnFocus: true,
  columnDefs: [ 
    { name: 'field1', enableSorting: false, enableCellEdit: false },
    { name: 'field2' },
    { name: 'field3', visible: false }
  ]
};

工作正常但是,我认为这不是真正的“角度方式”。感觉更像是一个jQuery小部件。如果你看一下像Angular Material这样的项目,它们在HTML模板和对象驱动中更具表现力。

对于我的实现,我最初想要使它非常富有表现力并暴露我使用的每个内部指令,然而,最终只是创建一个基本表。所以我对其他框架进行了一些研究,发现react有一个很好的架构,你可以在其中定义如下列:

React.render(
  <Table
    rowHeight={50}
    rowGetter={rowGetter}
    rowsCount={rows.length}
    width={5000}
    height={5000}
    headerHeight={50}>
    <Column
      label="Col 1"
      width={3000}
      dataKey={0}
    />
    <Column
      label="Col 2"
      width={2000}
      dataKey={1}
    />
  </Table>,
  document.getElementById('example')
);

我爱上了这种方法,它既简单又富有表现力。 90%的情况下,您只想自定义列模板。所以不要这样:

    $scope.gridOptions = {
    enableFiltering: true,
    rowTemplate: rowTemplate(),
    data: 'data',
    columnDefs: [
      { name: 'name' },
      { name: 'gender' },
      { name: 'company' },
      { name: 'widgets' },
      { 
        name: 'cumulativeWidgets', 
        field: 'widgets', 
        cellTemplate: '<div class="ui-grid-cell-contents" title="TOOLTIP">{{grid.appScope.cumulative(grid, row)}}</div>' 
          }
    ]
};

使用单元格模板,您可以执行以下操作:

<dt options="options" rows="data" class="material">
  <Column name="name" width="300"></Column>
  <Column name="Gender">
    <strong>{{value}}</strong>
  </Column>
  <Column name="Company"></Column>
</dt>

注意我如何使用React概念并将其与更具角度的概念配对,其中我将包括在列中具有模板的能力。

现在好了,问题。我希望init上的列,但不是之后。我想用实际的表替换它。问题是当我需要它时,我永远无法获得HTML。

所以on this line我尝试做类似的事情:

compile: function(tElem, tAttrs){
    var tags = z.getElementsByTagName('column');
    console.log(tags) // equals = []
    return {
        pre: function($scope, $elm, $attrs, ctrl){
        }
    };
}

但是当我试图将它们转移时,这些列永远不会存在(不是我想做的事情)。在控制器初始化之前,我需要一种方法来获取它们,模板将替换内部内容。这是一个plunkr

此外,由于我的指令是作用域的(我因为性能原因我想做的)我无法访问父作用域以使用外部内容编译内部模板。

此外,有关此设计范例的任何建议/想法吗?谢谢!

2 个答案:

答案 0 :(得分:3)

Try to use the template as a function, which returns the actual template string. The first parameter is the original html:

var tags;
return {
    template: function(element) { 
        tags = element[0].getElementsByTagName('column');
        return "<div>table</div>"     
    },
    compile: ...
}

答案 1 :(得分:1)

我只找到了一种奇怪的方式来实现你想要的东西。

在有人提供更好的解决方案之前,我的工作是plunker

$transclude服务添加到控制器并将transclude:'element'添加到指令

 app.directive("simple", function(){
    return {
        restrict: "EA",
        replace:true,
        transclude:'element',
        template:"<div>table</div>",
        compile: function(element, attributes, transclude){
            var tags = element[0].getElementsByTagName('column');
            console.log("compile", tags);
            console.log("transclude", transclude);
            return {
                pre: function(scope, element, attributes, controller, transcludeFn){
                    var tags = element[0].getElementsByTagName('column');
                    console.log("pre", tags);
                },
                post: function(scope, element, attributes, controller, transcludeFn){
                    var tags = element[0].getElementsByTagName('column');
                    console.log("post", tags);
                }
            }
        },
        controller: function($scope, $element, $transclude){
              $transclude(function(clone,scope){
                /* for demo am converting to html string*/
                console.log("From controller",angular.element(clone).find('column'));
              });
        }
    };
}); 

我测试了其他一些东西。但我只能使用此列并且只能进入控制器。