如何使用angularjs中的模板设置fieldname

时间:2014-01-18 06:52:57

标签: angularjs angularjs-directive

我希望字段的标签与字段验证属性进行一些交互。 我创建了一个工作示例的插件。

http://plnkr.co/edit/oNq5lmjtjRDaEkzKsrR2?p=preview

但在此示例中,fieldname是硬编码的。

我尝试通过范围变量将fieldname设置为模板。这不起作用:

http://plnkr.co/edit/yEl04xyFR5RWYCmI2bMH?p=preview

HTML:

<form name="myForm" ng-controller="ctrl">
  <fieldset field-name="{{model.fieldName}}" label-text="{{model.label}}" ng-model="model.value">
  <fieldset>
</form>

JavaScript的:

var app = angular.module('myApp',[]);
app.directive('fieldset', function(){
  return {
    template: '<label ng-class="{invalid:$parent.myForm[{{fieldName}}].$invalid}">{{lbl}}</label>: ' +
              '<input name="{{fieldName}}" ng-model="value" required>',
    restrict : 'E',
    scope : {
              value : '=ngModel',
              lbl : '@labelText',
              fieldName : '@'
            },

    link : function(scope, elem, attrs) {
      console.log(scope.$parent.myForm);
    }        
  }
})

app.controller('ctrl', function($scope) {
  $scope.model = {
    fieldName : 'myField',
    label : 'Label for Field',
    value : 6
  } 
});

范围内的字段名称。$ parent.myForm是“{{fieldName}}”而不是“myField”。但是在DOM中,fieldname按预期分配。 我该如何解决这个问题?

2 个答案:

答案 0 :(得分:4)

Stewie绝对正确。如果创建了ng-model指令,它将立即在表单中注册。如果你看一下角度源,你会发现ngModel是通过它们在数组form中的当前名称注册的:

if (control.$name) {
  form[control.$name] = control;
}

在您的情况下,这是“{{fieldName}}”。无法更改此name,因为它是数组中的键。那么我们可以做些什么来改变这个呢?如果我们查看 FormController API ,我们可以看到有删除($removeControl)或添加($addControl)控件的函数。这两个函数都需要NgModelController作为输入参数。例如。角度为我们的输入元素创建的NgModelController。我们可以通过以下方式访问此控制器:

var modelController = inputElement.controller('ngModel');

我认为我们现在已经掌握了所有信息来编写指令:

app.directive('fieldset', function(){
  return {
    template: '<label ng-class="{invalid:form[fieldName].$invalid}">{{lbl}}</label>: ' +
              '<input name="{{fieldName}}" ng-model="value" required>',
    restrict : 'E',
    require: '^form', // we need the parent NgFormController 
    scope : {
              value : '=ngModel',
              lbl : '@labelText',
              fieldName : '@'
         },

    link : function(scope, elem, attrs, formCtrl) {
       // get the NgModelController for the input element
       var modelCtrl = elem.find('input').controller('ngModel');

       // remove the ModelController from the FormController
       formCtrl.$removeControl(modelCtrl); 
       // set the right name
       modelCtrl.$name = scope.fieldName; 
       // add the namend ModelController to the FormController
       formCtrl.$addControl(modelCtrl); 

       // publish the FormController to the scope - so we don't need to mess around with the parent scope.
       scope.form = formCtrl;
    }
  }
})

我还建议将NgFormController发布到指令范围。所以你可以写下你的css条件:

form[fieldName].$invalid

instad of:

$parent.myForm[fieldName].$invalid

它更通用,因为您不需要知道表单的名称。

PLUNKR

答案 1 :(得分:2)

在插入子元素的视图表达式之前链接

ng-form指令。这就是为什么如果要使用角度形式验证,就不能拥有动态字段名称。

但是,在动态创建表单字段(通过ng-repeat)时,字段实际上不需要具有唯一的name属性。那是因为你被允许将每个表单元素包装到它自己的私有 ng-form范围中:

PLUNKER

app.controller('MainCtrl', function($scope) {
  $scope.fields = [
    {label: 'First Name', required: false},
    {label: 'Last Name', required: false},
    {label: 'Email', required: true}
  ];

});
<body ng-controller="MainCtrl">

  <form name="form" class="form-horizontal" ng-submit="save()" novalidate>

    <div class="form-group" ng-repeat="field in fields" ng-form="form">
      <label class="control-label" ng-class="{required: field.required}">{{field.label}}</label>
      <input 
        type="text" 
        name="field" 
        ng-model="field.value" 
        class="form-control" 
        ng-required="field.required"
      />
      <span 
        class="help-block error"
        ng-show="form.field.$dirty && form.field.$error.required"
      >{{field.label}} is required</span>
    </div>

    <div class="form-group">
      <button type="submit" class="btn btn-primary">Save changes</button>
      <button type="button" class="btn">Cancel</button>
    </div>

  </form>

</body>