1

我正在尝试创建一个通用指令,我想用它来显示一个灵活的、类似电子表格的数据输入表单。

我想将所有数据结构和格式信息放在 html 代码中,并让指令将其存储在作用域中以供以后使用。

这是我想使用的示例 HTML(“字段”元素中的信息是我想进入范围的信息):

<array title="Breakdown" data="data.breakdown">
  <field type="text" default="" name="descr">Description</field>
  <field type="number" default="0" name="price">Price</field>
  <field type="number" default="0" name="tax">Tax</field>
</array>

到目前为止的指令

.directive('array', function(){
  return {
    restrict: "E",
    replace: true,
    transclude: true,
    templateUrl: "js/array-template.html",
    compile: function(tElement, tAttrs, transclude) {
      var x=transclude(tElement);              
       return function(scope, element, attrs) {  //the linking function
       scope.title=attrs.title;
       }
    }
  }
}

变量 x 给了我一个 html 元素数组,但它不仅有“字段”元素,还有一堆空的“跨度”元素。如果需要,我可以使用它,但我怀疑有一种更简单的方法可以做到这一点。

4

1 回答 1

0

我找到了解决方案!

首先,我使用了 AngularJS 网站主页上的最后一个示例: http://angular.github.io/angularjs.org/#/list 这很好开始,但渲染的 HTML 代码总是包含一些垃圾,因为我不得不这样做使用 ng-transclude 指令来<FIELD>处理元素。

因此,我进一步查看并找到了一些动态创建模板的示例。这提供了更大的灵活性,我可以完全重写 HTML,而不会在结果代码中出现任何旧的片段。

我还必须使用不同的方法在指令之间进行通信,因为当主指令的模板中没有使用 ng-transclude 时,AngularJS 网站(共享控制器)中使用的方法会失效。我只对模块对象使用了一个附加属性,因为两个指令都属于同一个对象。

这是解决方案的完整代码。我希望它对某些人有用。

HTML:

<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body ng-app="flexlist">
        <array title="Breakdown" data="record">
            <field type="text" default="" name="descr" title="Description"></field>
            <field type="number" default="0" name="price" title="Price"></field>
            <field type="number" default="0" name="tax" title="Tax"></field>
        </array>
        <array title="test" data="record">
            <field type="text" default="" name="descr" title="Description"></field>
        </array>

    </body>
    <script src="js/angular.js"></SCRIPT>
    <script src="js/controller.js"></SCRIPT>
</html>

带有大量注释的 Javascript ;-)

function record(){  //a simple constructor to provide the data for the table
    return [{
          descr: "example",
          price: 10,
          tax: 0.07
      },
      {
          descr: "something else",
          price: 15,
          tax: 0.11

      }
  ];  
}

var mod=angular.module('flexlist', []);
mod.fields=[];  //container that is shared between directives
//the directive for <ARRAY>
mod.directive('array', function($compile){  //injecting the $compile service
    return {
        restrict: 'E',  //restricted to element only
        replace: true,
        scope:{
            title: '@title'  //getting the title attribute into the scope
        },
        link: function(scope,element,attr){
            //calling the function specified in the "data" attribute 
            //which should return the data to be filled into the table
            scope.source=window[attr.data]();  
            scope.fields=[];  //preparing the "field" variable in the scope
            //copying the data collected from the <field> elements into the scope
            angular.copy(mod.fields,scope.fields);   
            //preparing the collection for the next use 
            //(in case more than one <ARRAY> block is in a page
            mod.fields=[]; 
            newCont=angular.element(   //creating the template's HTML
'<FIELDSET>'+
    '<LEGEND>{{title}}</LEGEND>'+
    '<TABLE border=1>'+
        '<TR>'+
            '<TH ng-repeat="fld in fields">{{fld.title}}</TH>'+
        '</TR>'+
        '<TR ng-repeat="line in source">'+
            '<TD ng-repeat="fld in fields">{{line[fld.name]}}</TD>'+
        '</TR>'+
    '</TABLE>'+
'</FIELDSET>');
            //applying the Angular "magic" -- the directives in the template
            $compile(newCont)(scope);  
            element.replaceWith(newCont);  //replace the whole <ARRAY> element
        },
        controller: function($scope, $attrs){
            // nothing here yet
        }
    };
});

mod.directive('field',function(){
    return {
        require: '^array',  //the "^" means that <FIELD> has to be inside <ARRAY>
        restrict: 'E',  //restricted to be an element only
        link: function(scope,element,attrs){ //collecting the data from the element
           mod.fields.push({  //pushing the data into the collection object
               type: attrs.type,
               'default': attrs['default'],
               name: attrs.name,
               title: attrs.title                 
           });
        }
    };
});
于 2013-05-08T10:40:52.120 回答