3

我对 Angular 相当陌生,并试图制作一个指令来构造一个表单输入,通常是一个文本输入,但有时是一个基于输入是否与选项数组相关联的选择框。简化一下,我的代码大致如下所示:

html

<init ng-init = "ops = [
  {value:'hello',label:'Hello All'},
  {value:'bye',label:'Good-bye everyone'}]"></init>
<init ng-init = "fType = 
  {id:'greeting',label:'Greeting',type:'enum', 'options':ops}">    
</init>

<simpleselect field="fType" ng-Model="foomodel"></simpleselect>

{{foomodel}}

指示

.directive('simpleselect',function(){
  return {
    restrict: 'E',
    replace:true,
    template:[
      '<div><select ',
        'ng-if ="type=\'select\'"', 
        'name="{{field.id}}"',
        'ng-model="ngModel" ',
        'ng-options="option.value as option.label for option in field.options">',
      '</select>{{ngModel}}</div>',
    ].join(),
    scope:{
      field:'=',
      ngModel:'='
    },
    link:function(scope, elem, attrs, ctrl){
      scope.type = 'select';
    }
  }
});

这几乎可以工作。如果我删除选择框上的 ng-if,我的选择框和我的模型保持同步就好了。但我想要的是能够在指令中选择哪个控件。这是对 ng-if 的滥用吗?还有其他方法吗?

4

4 回答 4

0

template:function(element,attrs)如果使用角度版本 >=1.1.4可以使用

template:function(element,attrs){
    var template='<div>';
    var type= attrs.fieldType;
    if( type=='select'){
        template+='<select ng-options=......>';
    }
    if(  type=='text' ){
        template +='<input ......./>';
    }
    template +='</div>';
    return template;

}
于 2013-12-24T19:33:07.133 回答
0

正如几个人建议的那样,我本可以使用 ng-show,但我不想用我不使用的所有输入类型污染我的 DOM。我也可以用一个单独的属性列表来设置我的指令,而不是传入一个“字段”对象,然后在我的模板函数中观察它们以确定我输入的细节,比如 charlietfl 的解决方案。

相反,由于我想根据模型本身中的许多属性来确定要使用的输入类型控件,因此我选择使用 $compile 在我的指令的链接方法中解决我的控件呈现的很大一部分服务。然后,我既可以根据传入范围的模型做出宏观布局决策,又可以使用角度样式模板语法解决每个输入的细节。

对于一个简单的选择框,这将是矫枉过正,这里的其他两个答案中的任何一个都会更好,但是因为我希望我的指令确定控件是否应该是文本输入、文本区域、选择框、单选按钮或复选框,具体取决于仅根据模型的要求,我才需要能够先阅读模型,然后再进行编译。

在链接方法中进行渲染感觉有点不对,所以我并不是说我有一个很好的解决方案,但如果它可以帮助任何人,那就太好了。如果其他比我有更多 Angular 经验的人觉得这很冒犯,我也很乐意被理顺。:^)

这是指令中更复杂的复选框选项的示例:

    link:function(scope, elem, attrs, ctrl){
      ...some logic to examine the model to determine which input type to use...

    if(scope.type === 'checkbox'){
        if(typeof scope.ngModel === 'string') scope.ngModel = scope.ngModel.split(/[ ,]+/);
        tmp = [
        '<div class="option chk tall" ng-repeat="option in field.options">',
          '<label><input ng-model="ngModel" ng-value="option.value" ng-checked="ngModel.indexOf(option.value) > -1" name="{{field.id}}" type="checkbox" />{{option.label}}</label>',
          '<div class="description">{{option.description}}</div>',
        '</div>{{ngModel}}'].join('');
        elem.on('change',function(e){
          if(e.target.checked && scope.ngModel.indexOf(e.target.value) < 0) scope.ngModel.push(e.target.value);              
          if(!e.target.checked)
            scope.ngModel.splice(scope.ngModel.indexOf(e.target.value),1);
        });
      }

      elem.find('div').html(tmp);
      $compile(elem.contents())(scope);
    }

我一点也不喜欢通过点击来保持我的模型和 UI 同步的东西,但现在,我会接受它。

于 2013-12-26T20:19:00.543 回答
0

修改您的模板如下:

template: [
    '<div ng-if="field.type==\'select\'">', // <-- move ng-if here
        '<select name="{{field.id}}"',
                'ng-model="ngModel" ',
                'ng-options="option.value as option.label for option in field.options">',
        '</select>',
        '{{ngModel}}',
    '</div>'
].join(''),

另请注意,有几个错误:

1)。ng-if应该有==而不是=field.type而不是只是type

2)。.join('')代替.join()

演示http://jsfiddle.net/2YE3b/

于 2013-12-24T19:44:49.703 回答
0

我遇到了类似的问题,您实际上可以通过$parent.boundattribute访问父模型。

如评论中某处所述,ng-if 添加了一个子范围,因此模型不会向后更新。

在我的情况下 ng-show 不起作用,我必须真正删除 DOM 的一部分,这解决了问题。

<select ng-if="type='select'"
    name="{{field.id}}"
    ng-model="$parent.ngModel"
    ng-options="option.value as option.label for option in field.options">
</select>
于 2016-01-20T14:24:21.777 回答