使用ng-if的Angular指令似乎是松散的模型

时间:2013-12-24 19:12:00

标签: javascript angularjs angularjs-directive angular-ng-if

我对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 个答案:

答案 0 :(得分:0)

如果使用角度版本&gt; = 1.1.4

,可以使用template:function(element,attrs)
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;

}

答案 1 :(得分: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/

答案 2 :(得分:0)

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

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

对于一个简单的选择框,这本来是矫枉过正的,这里的其他两个答案中的任何一个都会更好,但因为我希望我的指令确定一个控件应该是文本输入,textarea,selectbox,单选按钮,或复选框仅取决于模型的要求我需要先读取模型然后用它进行编译。

在链接方法中进行渲染感觉有点不对,所以我并不是说我有一个很好的解决方案,但如果它对任何人有帮助,那就太好了。如果对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);
    }

我一点都不喜欢点击的东西,以保持我的模型和用户界面同步,但是现在,我将继续使用它。

答案 3 :(得分: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>