从子元素中提取数据并在指令中使用它

时间:2013-05-06 12:37:42

标签: angularjs angularjs-directive

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

我想把所有数据结构放在一起。格式化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元素数组,但它不仅包含&#34;字段&#34;元素,但一堆空&#34; span&#34;元素也是。如果需要,我可以使用它,但我怀疑这是一种更简单的方法。

1 个答案:

答案 0 :(得分: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                 
           });
        }
    };
});