使用AngularJS跳过嵌套表单验证

Ant*_*lle 31 javascript angularjs

如何使用AngularJS跳过嵌套表单的验证?即使其子表单无效,我也必须使外部表单有效.

在下面的示例中,外部表单应该是有效的(fOuter.$valid必须为true).默认情况下,它不是.有选择吗?

代码(jsFiddle):

<div ng-app ng-controller="Ctrl">  
    <ng-form name="fOuter">  
        <h3>Outer form (valid={{fOuter.$valid}})</h3>  
        <input type="text" name="txtOuter" ng-model="outer" placeholder="(required)" required />  
        <ng-form name="fInner">  
            <h3>Inner form (valid={{fInner.$valid}})</h3>  
            <input type="text" name="txtInner" ng-model="inner" placeholder="(required)" required />  
        </ng-form>  
    </ng-form>  
</div>
Run Code Online (Sandbox Code Playgroud)

小智 37

这是我的灵感来自mbernath的解决方案,它完全将形式本身与其父亲隔离开来.

该解决方案负责:

  • 表格有效期($ valid,$ invalid)
  • 表格互动($ pristine,$ dirty)
  • 嵌套表单的有效性和交互

在这个JSFiddle中看到它的实际效果.

angular.module('isolateForm',[]).directive('isolateForm', [function () {
    return {
        restrict: 'A',
        require: '?form',
        link: function (scope, elm, attrs, ctrl) {
            if (!ctrl) {
                return;
            }

            // Do a copy of the controller
            var ctrlCopy = {};
            angular.copy(ctrl, ctrlCopy);

            // Get the parent of the form
            var parent = elm.parent().controller('form');
            // Remove parent link to the controller
            parent.$removeControl(ctrl);

            // Replace form controller with a "isolated form"
            var isolatedFormCtrl = {
                $setValidity: function (validationToken, isValid, control) {
                    ctrlCopy.$setValidity(validationToken, isValid, control);
                    parent.$setValidity(validationToken, true, ctrl);
                },
                $setDirty: function () {
                    elm.removeClass('ng-pristine').addClass('ng-dirty');
                    ctrl.$dirty = true;
                    ctrl.$pristine = false;
                },
            };
            angular.extend(ctrl, isolatedFormCtrl);
        }
    };
}]);
Run Code Online (Sandbox Code Playgroud)

要使用它,只需调用指令"isolate-form":

<form name="parent">
    <input type="text" ng-model="outside"/>
    <ng-form name="subform" isolate-form>
        <input type="text" ng-model="inside"/>
    </ng-form>
</form>
Run Code Online (Sandbox Code Playgroud)

  • 这不再有效吗?因为现在在小提琴中,所有子形式在父形式有效之前必须是有效的,这与原始问题所要求的相反. (3认同)
  • 由于复制包含范围的对象的限制,这不再适用于Angular 1.6.`angular.copy`会产生错误(https://docs.angularjs.org/error/ng/cpws) (3认同)

mbe*_*ath 18

我遇到了同样的问题.在一个更大的表单内部,我需要一个带有几个控件的子表单,这些控件不应该触及父表单的状态.

这是我的解决方案:我编写了一个指令"null-form",它从父表单中删除子表单,并且不发送任何状态更改其父表单.

angular.module('nullForm',[]).directive('nullForm', [function () {
  return {
    restrict: 'A',
    require: '?form',
    link: function link(scope, element, iAttrs, formController) {

      if (! formController) {
        return;
      }

      // Remove this form from parent controller
      var parentFormController = element.parent().controller('form');
      parentFormController.$removeControl(formController);

      // Replace form controller with a "null-controller"
      var nullFormCtrl = {
        $addControl: angular.noop,
        $removeControl: angular.noop,
        $setValidity: angular.noop,
        $setDirty: angular.noop,
        $setPristine: angular.noop
      };

      angular.extend(formController, nullFormCtrl);
    }
  };
}]);
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

<form name="parent">
  <input type="text" ng-model="outside"/>
  <ng-form name="subform" null-form>
    <input type="text" ng-model="inside"/>
  </ng-form>
</form>
Run Code Online (Sandbox Code Playgroud)

"内部"的任何更改或否定验证都不会对"父级"产生影响.

然而,由于这个解决方案,有一个缺点:子窗体既不会有任何状态,也不会像ng-invalid等那样使用CSS类.要实现此目的,您需要从原始表单控制器重新实现此功能.


Chr*_*enz 11

至少使用Angular 1.5,似乎足以使用$removeControl以下方法从父级中删除嵌套表单:

module.directive('isolateForm', function() {
  return {
    restrict: 'A',
    require: '?form',
    link: function(scope, element, attrs, formController) {
      if (!formController) {
        return;
      }

      var parentForm = formController.$$parentForm; // Note this uses private API
      if (!parentForm) {
        return;
      }

      // Remove this form from parent controller
      parentForm.$removeControl(formController);
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

父母的原始状态和有效状态不再受嵌套形式的影响.

  • 请注意,使用此指令时,隔离的表单可以完美运行,包括验证. (2认同)

Max*_*tin 0

在 Angular 形式中可以嵌套。这意味着当所有子表单都有效时,外部表单也有效。

$valid因此,当内部形式之一无效时,无法使外部形式自动有效(通过密钥)。

尝试使用error.required

   <h3>Outer form (valid={{!fOuter.txtOuter.$error.required}})</h3>
Run Code Online (Sandbox Code Playgroud)

演示Fiddle

来自 Angular ngForm 文档

另一种方法应该是使用控制器,例如:

<h3>Outer form (valid={{isOuterFormValid}})</h3>
Run Code Online (Sandbox Code Playgroud)

控制器

$scope.isOuterFormValid = true;

// here, add listener on each input and change flag `isOuterFormValid`
... 
Run Code Online (Sandbox Code Playgroud)