【问题标题】:Getting form controls from FormController从 FormController 获取表单控件
【发布时间】:2014-01-21 09:14:57
【问题描述】:

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

我一直在查看源代码,发现 FormController 中有一个 controls 数组,这正是我要查找的数组。有没有办法访问这个值,或者扩展 FormController 以包含一个返回这个 controls 数组的函数?

编辑:Plnkr 演示

另外,我意识到从技术上讲,我可以检查密钥字符串中的第一个字符是否为“$”,但我想避免这种情况,以防 FormController/directive 在未来版本的 Angular 中发生变化。

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

编辑 3:我正在寻找的解决方案需要适用于不同结构的表单/模型。示波器上的模型是通过 AJAX 生成的,因此它们的结构已经设置好(我想避免为我已经通过 AJAX 接收的所有数据硬编码一个新结构)。此外,我希望在多个表单/模型中使用此表单提交过程,并且每个表单/模型都有不同的 JSON 结构——因为它们适用于我们的对象模型中的不同实体。这就是为什么我选择寻求一种方法来访问 FormController 中的controls 对象(我将在下面发布来自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
}

如您所见,表单本身具有私有可用的controls 数组。我想知道是否有办法扩展FormController,以便我可以公开该对象?或者创建一个公共函数,以便我至少可以查看私有数组?

【问题讨论】:

  • 您没有与控件关联的模型吗?您可以只观察模型以查看它们是否已更改,而不是循环浏览表单控件。
  • 我确实有模型,我也只是想避免做手表,因为 Form 指令中已经有手表来处理所有脏检查,对于大型表单,这可能会执行得很慢:(
  • 很好的问题,这与我正在寻找的相同(我的目标是在第一个错误显示后停止提交验证)。这段时间,您是否找到了比检查第一个字符 ($) 更好的替代解决方案?
  • 不幸的是,我仍在使用它来检查。如果我找到更好的方法,我会更新帖子。

标签: javascript angularjs angularjs-directive angularjs-ng-form


【解决方案1】:

要直接解决问题,请像这样修改@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)                        
     });

数组“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;
 }

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

    <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>

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

【讨论】:

  • 我完全忘记了我已经提交了这个问题,并最终做了与您在此处发布的内容非常相似的事情。实际上,我最终扩展了 ngSubmit 指令,以便它为我的所有具有 ngSubmit 函数的
    元素运行我的所有验证代码。
  • 我希望能在不妨碍您的情况下解决您的问题!使用指令可能是在 AngularJS 中做自定义东西的最佳方式,但是有很多内置的东西可以利用。
  • 只要照顾好 ng-form。此方法不处理它们。
  • 我相信这个解决方案只适用于设置了“name”属性的控件。
【解决方案2】:

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

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

【讨论】:

  • 我必须将 typeof value === 'object' &amp;&amp; 添加到您的 if 条件中。否则你会得到像“TypeError: Cannot read property 'hasOwnProperty' of undefined”这样的错误
  • @BryanLarsen 最好使用 angular.isObject(value) 。它还检查空值,因为typeof null 也是一个对象。
【解决方案3】:

在您的控制器中简单地尝试:

$scope.checkForm = function(myFormName){
     console.log(myFormName.$invalid);
}

更新:

<div ng-controller="MyController">
                <form name="form" class="css-form" novalidate>
                    <input type="text" ng-model="user.uname" name="uname" required /><br />
                    <input type="text" ng-model="user.usurname" name="usurname" required /><br />
                    <button ng-click="update(form)">SAVE</button>
                </form>
              </div>

app.controller('MyController',function($scope){
                $scope.user = {};
                $scope.update = function (form){
                    var editedFields = [];
                    angular.forEach($scope.user, function(value, key){
                        if(form[key].$dirty){
                           this.push(key + ': ' + value); 
                        }

                    }, editedFields);
                    console.log(editedFields);
                }
        });

【讨论】:

  • 我不认为我的问题很清楚,所以我添加了一个 plnkr 演示。我在检测表单是 $dirty 还是 $invalid 时没有任何问题。我的问题是我没有一个好的方法来循环遍历所有表单控件(字段本身)以确定哪些特定字段是 $dirty。我的主要目标是只提交已编辑的字段。
  • 这几乎是我目前所拥有的,但我的问题是我必须在我的范围内迭代一个非结构化/多维 JSON 对象,这就是为什么我d 更喜欢能够遍历 FormController 中的平面字段数组
【解决方案4】:

我想出了一个不错的解决方案,但它仍然不是我想要的。我从另一个涉及从字符串创建 JSON 对象的问题中挽救了一些代码,并提出了以下内容:

基本上,我以与模型绑定相同的方式命名我的字段,然后在调用 form_submit 时构建一个新对象以进行提交。

Plnkr demo

在演示中,如果您更改任何一个表单字段,然后点击提交,您将看到弹出的对象只有脏​​值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多