16

您将如何禁用或至少更改 Angular 验证 type=email 输入的方式?

目前,如果您使用 type=email,Angular 本质上会双重验证......因为浏览器(在本例中为 Chrome)验证电子邮件,然后 Angular 也会这样做。不仅如此,在 Chromefoo@bar有效的在 Angularjs 中无效。

我能找到的最好的是ng-pattern,但只是为输入类型ng-pattern添加了第三种模式验证..而不是替换 Angular 的电子邮件验证。呵呵

有任何想法吗?

4

5 回答 5

9

注意:此示例适用于 angular 1.2.0-rc.3。在其他版本上可能会有不同的表现

就像其他人所说的那样,关闭 angulars 默认输入验证有点复杂。您需要将自己的指令添加到输入元素并处理其中的内容。Sergey 的回答是正确的,但是如果您需要元素上的多个验证器并且不希望触发内置验证器,则会出现一些问题。

这是一个验证电子邮件字段的示例,其中添加了必需的验证器。我在代码中添加了注释来解释发生了什么。

输入元素

<input type="email" required>

指示

angular.module('myValidations', [])

.directive('input', function () {
  var self = {
      // we use ?ngModel since not all input elements 
      // specify a model, e.g. type="submit" 
      require: '?ngModel'
      // we need to set the priority higher than the base 0, otherwise the
      // built in directive will still be applied
    , priority: 1
      // restrict this directive to elements
    , restrict: 'E'
    , link: function (scope, element, attrs, controller) {
        // as stated above, a controller may not be present
        if (controller) {

          // in this case we only want to override the email validation
          if (attrs.type === 'email') {
            // clear this elements $parsers and $formatters
            // NOTE: this will disable *ALL* previously set parsers
            //       and validators for this element. Beware!
            controller.$parsers = [];
            controller.$formatters = [];

            // this function handles the actual validation
            // see angular docs on how to write custom validators
            // http://docs.angularjs.org/guide/forms
            //
            // in this example we are not going to actually validate an email
            // properly since the regex can be damn long, so apply your own rules
            var validateEmail = function (value) {
              console.log("Validating as email", value);
              if (controller.$isEmpty(value) || /@/.test(value)) {
                controller.$setValidity('email', true);
                return value;
              } else {
                controller.$setValidity('email', false);
                return undefined;
              }
            };

            // add the validator to the $parsers and $formatters
            controller.$parsers.push(validateEmail);
            controller.$formatters.push(validateEmail);
          }
        }
      }
  };
  return self;
})

// define our required directive. It is a pretty standard
// validation directive with the exception of it's priority.
// a similar approach must be take with all validation directives
// you would want to use alongside our `input` directive
.directive('required', function () {
  var self = {
      // required should always be applied to a model element
      require: 'ngModel'
    , restrict: 'A'
      // The priority needs to be higher than the `input` directive
      // above, or it will be removed when that directive is run
    , priority: 2
    , link: function (scope, element, attrs, controller) {
        var validateRequired = function (value) {
          if (value) {
            // it is valid
            controller.$setValidity('required', true);
            return value;
          } else {
            // it is invalid, return undefined (no model update)
            controller.$setValidity('required', false);
            return undefined;
          }

        };
        controller.$parsers.push(validateRequired);
      }
  };
  return self;
})
;

你有它。您现在可以控制type="email"输入验证。请使用适当的正则表达式来测试电子邮件。

需要注意的一点是,在此示例validateEmail中运行之前validateRequired。如果您需要validateRequired在任何其他验证之前运行,则只需将其添加到$parsers数组中(使用unshift而不是push)。

于 2013-10-22T19:57:47.873 回答
8

很简单。我必须更改电子邮件正则表达式以匹配业务需求,所以我制定了这个指令,使电子邮件正则表达式可定制。它基本上用我的自定义验证器覆盖了原始验证器。你不必弄乱所有的 $parsers 和 $formatters(除非我遗漏了一些东西)。所以我的指令是这样的......

module.directive('emailPattern', function(){
    return {
        require : 'ngModel',
        link : function(scope, element, attrs, ngModel) {

            var EMAIL_REGEX = new RegExp(attrs.emailPattern, "i");

            ngModel.$validators["email"] = function (modelValue, viewValue) {
                var value = modelValue || viewValue;
                return ngModel.$isEmpty(value) || EMAIL_REGEX.test(value);
            };
        }
    }
});

然后像这样使用它,提供您个人想要的任何电子邮件模式:

<input type="email" email-pattern=".+@.+\..+"/>

但是,如果您只想永久禁用它,那么您可以这样做。

module.directive('removeNgEmailValidation', function(){
    return {
        require : 'ngModel',
        link : function(scope, element, attrs, ngModel) {
            ngModel.$validators["email"] = function () {
                return true;
            };
        }
    }
});

然后像这样使用它...

<input type="email" remove-ng-email-validation>
于 2014-09-11T02:43:52.007 回答
7

在 HTML5 上,您可以使用表单的属性novalidate来禁用浏览器的验证:

<form novalidate>
    <input type="email"/>
</form>

如果您想在 angularjs 中创建自定义验证器,这里有一个很好的教程和示例:http ://www.benlesh.com/2012/12/angular-js-custom-validation-via.html

于 2013-01-18T23:58:14.207 回答
4

呼应nfiniteloop,您无需弄乱$parsers$formatters覆盖默认验证器。正如Angular 1.3 文档中所引用的,$validators 对象可以在 ngModelController 上访问。使用自定义指令,您可以根据需要编写任意数量的不同电子邮件验证函数,并在任何地方调用它们。

这里有一个来自tuts 的非常好的标准电子邮件格式正则表达式:你现在应该使用的 8 个正则表达式(可能与 Angular 的默认值 idk 相同)。

var app = angular.module('myApp', []);

app.directive('customEmailValidate', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {

      var EMAIL_REGEXP = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;

      ctrl.$validators.email = function(modelValue, viewValue) {
        if (ctrl.$isEmpty(modelValue)) {
          // consider empty models to be valid
          return true;
        }

        if (EMAIL_REGEXP.test(viewValue)) {
          // it is valid
          return true;
        }

        // it is invalid
        return false;
      };
    } 
  };
});

这是一个完全删除验证的方法:

var app = angular.module('myApp', []);

app.directive('noValidation', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$validators.email = function(modelValue, viewValue) {
        // everything is valid
        return true;
      };
    } 
  };
});

要在您的标记中使用:

<!-- 'test@example.com' is valid, '@efe@eh.c' is invalid -->
<input type="email" custom-email-validate>

<!-- both 'test@example.com' and '@efe@eh.c' are valid -->
<input type="email" no-validation>
于 2015-02-22T03:34:50.047 回答
2

在我的项目中,我做了这样的事情(自定义指令擦除所有其他验证,包括由 angularjs 安装的验证):

angular.module('my-project').directive('validEmail', function() {
    return {
        require: 'ngModel',
        link: function(scope, elm, attrs, ctrl){
            var validator = function(value){
                if (value == '' || typeof value == 'undefined') {
                    ctrl.$setValidity('validEmail', true);
                } else {
                    ctrl.$setValidity('validEmail', /your-regexp-here/.test(value));
                }
                return value;
            };

            // replace all other validators!
            ctrl.$parsers = [validator];
            ctrl.$formatters = [validator];
        }
    }
});

使用方法(注意novalidate,需要关闭浏览器验证):

<form novalidate>
    <input type="email" model="email" class="form-control" valid-email>
于 2013-09-13T08:20:47.947 回答