保持Angular表单验证DRY

时间:2015-06-15 22:05:18

标签: angularjs validation dry

我有一个可能有15-20个字段的表单。它们中的每一个都包含一个如下所示的属性:

ng-class='addressForm.city.$invalid && addressForm.city.$touched ? "error" : ""'

所以我将那长串代码重复了15-20次。这让我的DRY警报响起了大声。

我可以设计自己的方式让它更干,但我不想重新发明轮子。是否有一种通常被接受的方式来保持Angular表单验证DRY?

4 个答案:

答案 0 :(得分:0)

如果只是造型使用CSS。

Angular会将.ng-invalid.ng-touched添加到无效和触及的输入元素中。

或者你可以将整个事情包装在类似

的指令中
angular.module('module').directive('errorClass', function(){
    return{
        require: 'ngModel',
        link: function(scope, el, attr, model) {
             function setClass() {
                if(model.$touched && model.$invalid) {
                   if(!el.hasClass('error')) { 
                      el.addClass('error');
                   }
                } else {
                    el.removeClass('error');
                }
             }

             scope.$watch(function(){ return model.$touched; }, setClass);
             scope.$watch(function(){ return model.$invalid; }, setClass);
        }
    }
});

此外我还没有实际使用过该指令,因此可能需要进行一些调整。

答案 1 :(得分:0)

正如@lain所说,如果字段无效,则不必添加另一个类(如error),Angular默认为您添加,它只是名称不同({{1} })。 您可以看到如何使用here(来自Angular的官方表单示例)。

如果您仍想以自己的方式执行此操作,则使用ng-invalid指令执行我的最新评论。

html:

ngChange

变更事件:

<input type="text" ng-model="addressForm.city" required ng-change="fieldChanged(this, 'city')">

这不是一个好的做法(操纵控制器中的DOM),你应该在一个指令中实现它,但是将指令绑定到每个字段会增加观察者和我个人尽量避免使用许多观察者。

更优雅的选择是将此$scope.fieldChanged = function(el, fieldName){ if($scope.addressForm[fieldName].$invalid && $scope.addressForm[fieldName].$touched) angular.element(el).addClass('error'); else angular.element(el).removeClass('error'); } ngChange结合使用,或者只是在控制器中使用简单的DOM操作。这是你的选择:)

答案 2 :(得分:0)

我最终为此创建了自己的指令。我相信以下指令在应用时将与此等效:

form(name='addressForm')
  input(
    type='text'
    name='city'
    ng-class='addressForm.city.$invalid && (addressForm.city.$touched || addressForm.$submitted) ? "error" : ""'
  )

而不是所有这些,我可以做到:

form(name='addressForm')
  input(
    type='text'
    name='city'
    validate-for='addressForm'
  )

该指令将检查有效性:

  • 模糊
  • 表单提交
  • 价值变动

这里是代码(ES6):

'use strict';

class ValidateFor {
  constructor() {
    this.restrict = 'A';
    this.require = 'ngModel';

    this.link = ($scope, $element, $attrs, ngModel) => {
      var form = $scope[$attrs.validateFor];
      var field = form[$element.attr('name')];

      $scope.$on('form-submitted', () => {
        this.checkForErrors(field, $element);
      });

      $scope.$watch(() => ngModel.$modelValue, () => {
        if (field.$touched) {
          this.checkForErrors(field, $element);
        }
      });

      $element.bind('blur', () => {
        this.checkForErrors(field, $element);
      });
    };
  }

  checkForErrors(field, $element) {
    if (field.$invalid) {
      $element.addClass('error');
    } else {
      $element.removeClass('error');
    }
  }
}

ValidateFor.$inject = [];

您甚至可以消除在validate-for中提供表单名称的必要性。我这样做是因为我有一些嵌套的表单情况。

答案 3 :(得分:0)

valdr看起来很棒。我还没有使用它,但我会尝试一下,稍后会更新这篇文章。