简体   繁体   English

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

[英]Angular directives with ng-if seem to loose model

I am fairly new to Angular and trying to make a directive that will construct a form input, usually a text-input, but sometimes a select box based on whether or not the input is associated with an array of options. 我对Angular很新,并试图制作一个指令,它将构造一个表单输入,通常是一个文本输入,但有时候是一个基于输入是否与一个选项数组相关联的选择框。 Simplifying down, my code looks roughly like this: 简化,我的代码大致如下:

html 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 指示

.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';
    }
  }
});

This almost works. 这几乎可行。 If I remove the ng-if on the select box, my select box and my model stay in sync just fine. 如果我在选择框中删除ng-if,我的选择框和我的模型保持同步就好了。 But what I want is to be able to choose which control within the directive. 但我想要的是能够选择指令中的哪个控件。 Is this a misuse of ng-if and is there another path? 这是对ng-if的误用吗?还有其他途径吗?

Can use template:function(element,attrs) if using angular version >=1.1.4 如果使用angular version> = 1.1.4 template:function(element,attrs)可以使用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;

}

Modify your template as follows: 修改模板如下:

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(''),

Also note there are couple of errors: 另请注意,有几个错误:

1). 1)。 ng-if should have == instead of = and field.type instead of just type ng-if应该有==而不是=field.type而不仅仅是type

2). 2)。 .join('') instead of .join() .join('')而不是.join()

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

As a couple of folks suggested, I could have used ng-show, but I didn't want to pollute my DOM with all the input types I was not using. 正如一些人建议的那样,我本可以使用ng-show,但我不想用我没有使用的所有输入类型来污染我的DOM。 I also could have set my directive with a list of individual properties instead of passing in a 'field' object and then watching them in my template function to determine the particulars of my input, like charlietfl's solution. 我也可以用一个单独的属性列表设置我的指令,而不是传入一个'field'对象,然后在我的模板函数中观察它们以确定我输入的细节,比如charlietfl的解决方案。

Instead, since I want to determine which input type control to use based on a number of attributes in the model itself, I have chosen to resolve a good portion of the rendering of my control in the link method of my directive, using the $compile service. 相反,由于我想根据模型本身的许多属性确定要使用哪个输入类型控件,我选择使用$ compile在我的指令的链接方法中解析我的控件的很大一部分渲染。服务。 Then I can both make macro layout decisions based on the model I pass into scope and still resolve the particulars of each input using angular style template syntax. 然后我可以根据我传入范围的模型做出宏布局决策,并且仍然使用角度样式模板语法解决每个输入的细节。

For a simple selectbox, this would have been overkill and either of the two other answers here would have been better, but because I want my directive to determine if a control should be a text input, textarea, selectbox, radio buttons, or checkboxes depending only on the requirements of the model I need to be able to read the model first and then compile with it. 对于一个简单的选择框,这本来是矫枉过正的,这里的其他两个答案中的任何一个都会更好,但因为我希望我的指令确定控件是否应该是文本输入,textarea,selectbox,单选按钮或取决于复选框只有模型的要求我才能首先读取模型,然后用它进行编译。

Doing rendering in the link method feels a bit wrong, so I don't mean to be saying I have a great solution, but if it helps anyone, that's great. 在链接方法中进行渲染感觉有点不对,所以我并不是说我有一个很好的解决方案,但如果它对任何人都有帮助,那就太好了。 If others with more experience with Angular than me find that offensive, I would also love to be straightened out. 如果对Angular有更多经验的人比我发现那些令人反感的话,我也会喜欢被理顺。 :^) :^)

Here is an example of my more complicated checkbox option within the directive: 这是我在指令中更复杂的复选框选项的示例:

    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);
    }

I am not at all in love with the on-click stuff to keep my model and UI in sync, but for now, I am going to live with it. 我一点也不喜欢点击的东西,以保持我的模型和UI同步,但是现在,我将继续使用它。

I had a similar problem and you can actually access the parent model via $parent.boundattribute . 我遇到了类似的问题,您实际上可以通过$ parent.boundattribute访问父模型。

As described somewhere in the comments, ng-if adds a subscope and thus the model does not update backwards. 如评论中某处所述,ng-if添加了一个子范围,因此模型不会向后更新。

In my case ng-show would not work, I had to really remove the part of the DOM and this solved the problem. 在我的情况下,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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM