【问题标题】:how to set the fieldname using a template in angularjs如何在angularjs中使用模板设置字段名
【发布时间】:2014-01-20 06:58:01
【问题描述】:

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

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

但在本例中,字段名是硬编码的。

我尝试通过范围变量将字段名设置到模板中。这不起作用:

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

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

【问题讨论】:

  • 遗憾的是,如果你想使用 ng-form,name 属性不能动态设置,这是因为在插入 name 属性中的表达式之前链接了 ng-form 指令。你打算在 ng-repeat 中使用你的 fieldset 指令吗?如果没有,那么您只需将name 设置为“arbitraryDummyString”,您的表单验证就会起作用。
  • 不幸的是,它与数据库字段一起使用,通常与 ng-repeat 一起使用。没有办法在指令中添加带有绑定的属性吗?在这种情况下,我可以先使用一个 dummyName,然后在我的链接功能中将绑定添加到真实名称并在链接功能中创建关联的键,如下所示:link : function(scope, elem, attrs) { var form = scope.$parent.myForm; var name = scope.fieldName; form[name] = form.dummyName; form[name].$name = name; delete form.dummyName; elem.find('input').attr('name',name); }

标签: angularjs angularjs-directive


【解决方案1】:

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

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

在您的情况下,这是“{{fieldName}}”。这个name 不能更改,因为它是数组中的键。那么我们能做些什么来改变这一点呢?如果我们查看 FormController API,我们可以看到有一些函数可以删除 ($removeControl) 或添加 ($addControl) 控件。这两个函数都需要 NgModelController 作为输入参数。例如。 angular 为我们的输入元素创建的 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

代替:

$parent.myForm[fieldName].$invalid

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

PLUNKR

【讨论】:

  • 这是一个很好的答案。我希望所有的答案都是信息丰富且解释清楚的。
【解决方案2】:

ng-form 指令在插入子元素上的视图表达式之前被链接。这就是为什么如果您想使用 Angular 表单验证,您不能使用动态字段名称。

但是,当动态创建表单字段时(通过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>

【讨论】:

  • 好的,这样就更清楚了。但是您能否在指令中展示一个带有 ng-repeat 和隔离范围的示例?在一个孤立的范围内,我的范围内没有表单来访问该字段。因此我尝试像 scope.$parent.myFormName.myFieldName 一样访问它——但这似乎不是正确的方法。
  • 请参阅@michael 的回答以获取有关如何从隔离范围内访问 ngFormController 的信息。
猜你喜欢
  • 1970-01-01
  • 2021-01-27
  • 2013-05-15
  • 2015-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-24
相关资源
最近更新 更多