how to set the fieldname using a template in angularjs

人走茶凉 提交于 2019-12-06 05:21:51

Stewie is absolutely right. If the ng-model directive is created it will immediately be registered at the form. If you have a look at the angular sources you will find that the ngModels are registered by their current name in the array form:

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

In your case this is '{{fieldName}}'. This name can not be changed, because it is the key in the array. So what can we do to change this? If we have a look at the FormController API we can see there are functions to remove ($removeControl) or add ($addControl) controls. Both functions require the NgModelController as input parameter. E.g. the NgModelController that angular has created for our input element. We have access to this controller by:

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

I think we have now all information together to write the directive:

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

I would also suggest publish the NgFormController to the directives scope. So you may write your css condition:

form[fieldName].$invalid

instad of:

$parent.myForm[fieldName].$invalid

It is more generic, because you don't need to know the name of your form.

PLUNKR

ng-form directive is linked before the view expressions on child elements are interpolated. This is why you can't have dynamic field names if you want to make use of angular form validation.

But, when creating the form fields dynamically (through ng-repeat), the fields don't really need to have unique name attribute. That's because you're allowed to wrap each form element into it's own private ng-form scope:

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>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!