如何将Angular指令存储在作用域变量中?

3
我正在使用AngularJS实现一个表单生成器,需要在运行时插入和重新排序指令。 甚至不知道从哪里开始寻找 - 所有示例似乎都只演示指令的静态树。实现动态行为的两种选择是:a)即时编译和插入模板和b)使用所有可能指令的巨大ng-switch。这两种方法都很丑陋。
有人能提出更好的实现吗?
以下是我认为表单构建器在理想情况下应该如何看待的JS和HTML代码,请帮助我填写三个TODO实例。 JSFiddle JavaScript:
angular.module('components', [])
  .directive('checkbox', function() {
    return {
      restrict: 'E',
      template: '<div class=f><input type=checkbox>{{name}}</input></div>'
    };
  })
  .directive('textfield', function() {
    return {
      restrict: 'E',
      template: '<div class=f><input type=text placeholder="{{name}}"></input></div>'
    };
  })

function FormBuilder($scope, $locale) {
    $scope.title = 'test form';
    $scope.fields = [];  
    $scope.add_checkbox = function() {
        console.log('adding checkbox');
        var field = null; // TODO: how do I instantiate a directive?
        $scope.fields.push(field);
    };
    $scope.add_textfield = function() {
        console.log('adding textfield');
        var field = null; // TODO: how do I instantiate a directive?
        $scope.fields.push(field);
    };
}

HTML:

<div ng-app=components ng-controller=FormBuilder>
    <button ng:click="add_checkbox()">new checbox</button>
    <button ng:click="add_textfield()">new text field</button>
    <h3>{{ title }}</h3>
    <checkbox></checkbox>

    <textfield></textfield>

    <div ng:repeat="field in fields">
        <!-- TODO field.get_html() - how? -->
    </div>
</div>
1个回答

2
我认为你有几种方法可以实现这个功能,正如你所提到的,既然你不想使用 switch 语句,你可以为每个指令创建一个模板文件,例如 checkbox.html、textfield.html,并将指令放入每个模板中。然后在添加字段时,使用 ['checkbox.html', 'textarea.html'] 填充您的字段数组,只需在循环中简单地使用 <div ng-include='field'></div>
这是一个演示:http://plnkr.co/edit/w6n6xpng6rP5WJHDlJ3Y?p=preview 你也可以创建另一个指令,在其中传递输入类型并将其注入模板。这里有一个演示,它允许您避免声明模板并让指令根据字段类型创建它们: http://plnkr.co/jhWGuMXZTuSpz8otsVRY
<div ng:repeat="field in fields">
  <master-field type='field'></master-field>
</div>

这个“master-field”指令只是根据字段的值编译模板。
.directive('masterField', function($compile) {
   return {
      restrict: 'E',
      replace:true,
      transclude: true,
      scope:{
         type:'='
      },
      template: '<div></div>',
      controller: function ( $scope, $element, $attrs ) {},
      link: function(scope, element, attrs) {

       element.append( $compile('<' + scope.type+ '/></' +scope.type + '>')(scope) ); 
      }
    };
 })

非常好的回答,感谢你花这么多时间来回答。但还有一件事情缺失了,那就是如何将特定于字段的数据绑定到动态模板上?我的意思是如果 $scope.fields = [{type: 'checkbox', name: 'agree', selected: false}, {type: 'textfield', name: 'email', defvalue: 'foo@bar.com'}] 并且我想要 {{name}} 在模板中解析为字段的名称,而不是最顶层控制器的 $scope.name。我该如何实现这样的功能呢? - Boycott Russia
我认为这是一个非常好的问题,但它是一个单独的问题。您的所有指令都没有被构建为具有范围:http://docs.angularjs.org/guide/directive#directivedefinitionobject - lucuma
你可能需要查看这个问题:http://stackoverflow.com/questions/16358706/using-directives-inside-directives-causes-binding-issues - lucuma
好的,这正是我一开始想要解决的问题 :) 我会接受你的答案,并尝试重新表述成一个新问题。 - Boycott Russia
没问题,这里有几个关于指令双向绑定的问题,但是如果像我的答案一样编译,可能会更棘手一些。 - lucuma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接