从FormController获取表单控件

rob*_*oth 29 javascript angularjs angularjs-directive angularjs-ng-form

我需要一种方法来遍历AngularJS表单的已注册控件.本质上,我正在尝试获取所有$ dirty控件,但是没有控件数组(FormController除了包含控件本身之外还有许多不同的属性/函数 - 每个都作为它自己的对象).

我一直在看源代码,我看到controlsFormController中有一个数组正是我正在寻找的数组.有没有办法访问此值,或扩展FormController以包含一个返回此controls数组的函数?

编辑:Plnkr演示

另外,我意识到技术上我可以检查键字符串中的第一个字符"$",但是我希望避免在未来版本的Angular中FormController /指令发生变化的情况.

编辑2:另一个澄清:我所有这一切的目标是能够确定哪些特定字段是$ dirty,是否循环遍历整个控件列表(不包括$ dirty,$ invalid,$ error,$ name,以及生活在Form对象中的其他属性,或者通过扩展FormController并创建一个只返回当前脏的控件(并且不等于它们的起始值)的函数

编辑3:我正在寻找的解决方案需要适用于不同结构的表单/模型.范围上的模型是通过AJAX生成的,因此它们的结构已经设置好了(我想避免为我已经通过AJAX接收的所有数据硬编码新结构).此外,我希望在多个表单/模型中使用此表单提交过程,并且每个表单都具有不同的JSON结构 - 因为它们适用于对象模型中的不同实体.这就是为什么我选择了一种方法来访问controlsFormController中的对象(我将从FormController下面发布代码),因为它是我可以获得所有字段的平面数组的唯一地方.

function FormController(element, attrs) {


var form = this,
      parentForm = element.parent().controller('form') || nullFormCtrl,
      invalidCount = 0, // used to easily determine if we are valid
      errors = form.$error = {},
      controls = [];

  // init state
  form.$name = attrs.name || attrs.ngForm;
  form.$dirty = false;
  form.$pristine = true;
  form.$valid = true;
  form.$invalid = false;

  parentForm.$addControl(form);

  // Setup initial state of the control
  element.addClass(PRISTINE_CLASS);
  toggleValidCss(true);

  // convenience method for easy toggling of classes
  function toggleValidCss(isValid, validationErrorKey) {
    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
    element.
      removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
      addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
  }

  /**
   * @ngdoc function
   * @name ng.directive:form.FormController#$addControl
   * @methodOf ng.directive:form.FormController
   *
   * @description
   * Register a control with the form.
   *
   * Input elements using ngModelController do this automatically when they are linked.
   */
  form.$addControl = function(control) {
    controls.push(control);

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

  /**
   * @ngdoc function
   * @name ng.directive:form.FormController#$removeControl
   * @methodOf ng.directive:form.FormController
   *
   * @description
   * Deregister a control from the form.
   *
   * Input elements using ngModelController do this automatically when they are destroyed.
   */
  form.$removeControl = function(control) {
    if (control.$name && form[control.$name] === control) {
      delete form[control.$name];
    }
    forEach(errors, function(queue, validationToken) {
      form.$setValidity(validationToken, true, control);
    });

    arrayRemove(controls, control);
  };

  // Removed extra code
}
Run Code Online (Sandbox Code Playgroud)

如您所见,表单本身具有controls私有的数组.我想知道是否有办法让我扩展FormController所以我可以将该对象公之于众?或者创建一个公共函数,这样我至少可以查看私有数组?

fai*_*tha 19

要直接解决问题,请修改@ lombardo的答案;

     var dirtyFormControls = [];
     var myForm = $scope.myForm;
     angular.forEach(myForm, function(value, key) {
         if (typeof value === 'object' && value.hasOwnProperty('$modelValue') && value.$dirty)
             dirtyFormControls.push(value)                        
     });
Run Code Online (Sandbox Code Playgroud)

然后,数组'dirtyFormControls'将包含脏的表单控件.

您还可以使用此技巧在表单提交时显示"必需"验证和所有其他验证的错误消息.在submit()函数中,您将执行类似的操作;

 if (form.$invalid) {
     form.$setDirty();              
     angular.forEach(form, function(value, key) {
         if (typeof value === 'object' && value.hasOwnProperty('$modelValue'))
             value.$setDirty();                        
     });
    //show user error summary at top of form.
     $('html, body').animate({
         scrollTop: $("#myForm").offset().top
     }, 1000);
     return;
 }
Run Code Online (Sandbox Code Playgroud)

在您的表单中,您将显示错误消息

    <span ng-messages="myForm['subject-' + $index].$error" ng-show="myForm['subject-' + $index].$dirty" class="has-error">
        <span ng-message="required">Course subject is required.</span>
    </span>
Run Code Online (Sandbox Code Playgroud)

当您使用'ng-repeat'或类似的东西动态生成控件时,上述解决方案很有用.


lom*_*rdo 11

您可以使用以下代码迭代控件:

    var data = {};
    angular.forEach(myForm, function (value, key) {
        if (value.hasOwnProperty('$modelValue'))
            data[key] = value.$modelValue;
    });
Run Code Online (Sandbox Code Playgroud)

  • 我必须在你的if条件中添加`typeof value ==='object'&&`.否则,您可能会收到类似"TypeError:无法读取属性'hasOwnProperty'未定义"的错误 (8认同)