jQuery Validate和Masked Input之间的冲突

时间:2010-12-09 14:09:12

标签: jquery validation maskedinput

我的表单同时使用jQuery ValidateMasked Input表示电话号码和美国邮政编码字段。

例如,对于美国邮政编码,屏蔽输入仅允许输入数字,并强制格式为“99999”或“99999-9999”(其中9可以是任意数字)。验证规则要求相同。但在某些情况下,验证字段在实际上应该有效时将其标记为无效。

代码细节

jQuery Validate在邮政编码字段中使用的正则表达式为^\d{5}$|^\d{5}\-\d{4}$

我使用蒙面输入的面具是.mask('99999?-9999')

重现的步骤

当我执行以下操作时,会产生它们之间的冲突:

  • 填写无效的邮政编码(例如,三位数)
  • 远离田地。 Masked Input删除输入(预期行为),jQuery Validate将其标记为无效,因为它是空白的(也是预期的)。
  • 返回邮政编码区并填写有效的 5位数压缩文件。
  • 远离田地。 仍然标记为无效。这是意外的

如果我填写一个9位数的邮政编码,这个问题会发生

假设

我认为这个错误是因为在5位数字拉链的情况下,Masked Input已暂时插入“-____”以向用户显示他们可以选择输入短划线和另外4位数字。这在模糊时被删除,但在删除之前,该字段已经过验证并失败,因为不允许使用下划线。

这个假设得到以下事实的支持:如果随后重新验证表单,则zip字段将通过。我有两种方式:

  • 提交表格;单击提交按钮,zip字段通过,表单提交时,将重新验证所有字段。
  • 设置重新验证该特定字段的blur事件。例如:

    $(“#zipcode”)。blur(function(){$(this).closest('form')。validate()。element($(this));});

这可以作为一个hacky解决方案,但不是很令人满意,因为1)默认设置已经重新验证模糊,所以这是重复的,2)它需要额外的代码除了正常的验证规则。

还有其他人遇到过这个问题吗? 您是否拥有比设置其他模糊事件监听器更优雅的解决方案

更新:应用hacky解决方案

即使应用上面的hacky解决方案也不如我想的那样好用。例如,这不起作用:

$appDiv.delegate('input,select,textarea','blur',function(){
  $(this).closest('form').validate().element($(this));
});

......也不是这样:

$('input,select,textarea').live('blur',function(){
  $(this).closest('form').validate().element($(this));
});

......但这样做:

$('input,select,textarea').each(function(){
  $(this).blur(function(){
    $(this).closest('form').validate().element($(this));
  });
});

由于这些元素是由AJAX加载的,因此每次加载表单部分时都必须运行.each版本。

7 个答案:

答案 0 :(得分:11)

我尝试了以下解决方案,它就像一个魅力。

$("[data-input-type=phone]", "body")
  .mask("(999) 999 99 99")
  .bind("blur", function () {
    // force revalidate on blur.

    var frm = $(this).parents("form");
    // if form has a validator
    if ($.data( frm[0], 'validator' )) {
      var validator = $(this).parents("form").validate();
      validator.settings.onfocusout.apply(validator, [this]);
    }
  });

触发问题的是事件排序。 当一个元素被屏蔽时,它会被blur上的maskedinput插件验证,但同一个元素会被focusout事件上的验证器插件验证(这是非ie浏览器上的模糊包装)在蒙面输入模糊之前。

在这种情况下,当验证器检查值时,input元素的值为"(___) ___ __ __"。当代码达到maskedinput的blur事件时,插件会测试并清除该值,因为它不是有效的输入。

每个验证案例的验证结果可能不同。例如,required规则将成功传递,因为element具有值。即使我们将输入留空,因此非必需number字段也会失败,因为"999"之类的掩码可能会被测试为12_

上面的代码测试屏蔽输入的形式是否附加了验证,并调用focusout事件处理程序。由于我们的处理程序是最新的,希望它最后会被调用。

警告,代码只是复制验证插件的行为。它可能会工作十年,但如果验证插件决定做的事情与现在不同,可能会失败。

真诚

答案 1 :(得分:9)

我实际上是在寻找这个确切问题的答案。结束了找出更可靠的解决方法。

由于我正在为zipcode定义我自己的验证器方法,因此我修改了它,以便在我从值中删除占位符后,如果zipcode的长度为6,则会删除连字符。

看起来像这样:

$.validator.addMethod("zipcode", function(postalcode, element) {
            //removes placeholder from string
            postalcode = postalcode.split("_").join("");

            //Checks the length of the zipcode now that placeholder characters are removed.
            if (postalcode.length === 6) {
                //Removes hyphen
                postalcode = postalcode.replace("-", "");
            }
            //validates postalcode.
            return this.optional(element) || postalcode.match(/^\d{5}$|^\d{5}\-\d{4}$/);
        }, "Please specify a valid zip code");

因此,我验证的邮政编码将通过输入插件添加占位符,并且如果输入的邮政编码仅包含5位数字(包括连字符),则删除连字符。所以它会正确验证它。

答案 2 :(得分:7)

只需挂钩mask()函数并添加一些额外的逻辑,以在默认蒙版的模糊逻辑之后触发自己的模糊逻辑:

//Store the original mask function
var origMaskFn = $.fn.mask;

$.fn.mask = function (mask, settings) {

    //Call the original function applying the default settings
    origMaskFn.apply(this, [mask, settings]);

    //Manually validate our element on blur to prevent unobtrusive messages
    //from showing before the mask is properly scrubbed
    $(this).bind('blur', function () {
        var $form = $(this).parents('form');
        if (!$form.exists())
            return;

        var validator = $form.validate().element($(this));
    });
}

另外,您可能会注意到'exists()'函数。这是我在jQuery选择器中使用的很多东西:

//Function to detect if a jQuery elements exists.  i.e.:
//      var $element = $(selector);
//      if($element.exists()) do something...

$.fn.exists = function () {
    return this.length !== 0;
}

答案 3 :(得分:5)

我遇到了类似的问题,设法解决了将默认占位符字符更改为空字符串的问题。

我使用的是.mask('9?99');并且使用简单的“数字”规则进行验证,并且遇到了同样的冲突。

我将掩码声明更改为.mask('9?99',{placeholder:''});并且......没有更多冲突。 :)

在您的情况下可能存在问题,因为邮政编码中的-始终由掩码插件插入表单中。我认为您可以将正则表达式更改为^\d{5}\-$|^\d{5}\-\d{4}$(在两种情况下都匹配短划线),然后它应该验证。

无论如何,你刚刚发布了,可能不再需要这个了,但也许它会帮助别人。 :)

答案 4 :(得分:1)

您执行绑定的顺序是否重要?例如,

之间是否存在差异
$(function() {
  var $form = $("#myForm"), $zip = $("#zip");
  $zip.mask("99999?-9999");
  $form.validate();
});

$(function() {
  var $form = $("#myForm"), $zip = $("#zip");
  $form.validate();
  $zip.mask("99999?-9999");
});

我认为绑定应按顺序触发。

答案 5 :(得分:0)

我尝试了一些解决方案,但没有一个对我有用,我正在使用'bootstrapValidator'(http://bootstrapvalidator.com/)和'jquery.maskedinput'(http://digitalbush.com/projects/masked-input-plugin/)所以如果有人仍有这个问题,我的解决方案是:

我的输入标记如下:

<input type="text" class="form-control" id="telefone" placeholder="(__) ____-_____" name="telefone" required>

完整的脚本如下:

$(document).ready(function() {
   var telefone = $('#telefone'), //THAT'S MY INPUT WITH MASK
       form = telefone.parents("form"), //THAT'S MY FORM WITH THE VALIDATE
       alteredField = false; //THAT'S A FLAG TO SSE IF THE INPUT WAS ALTERED

            // APPLY MY MASK
            telefone.mask('(99) 9999-9999?9');

            // FOCUS ON ANY INPUT
            form.find('input[type=text]').focus(function(){
                // REMOVE THE VALIDATION STATUS
                $(form).data('bootstrapValidator').updateStatus($(this).attr('name'), 'NOT_VALIDATED');
                // ENABLE THE SUBMIT BUTTON
                $(form).data('bootstrapValidator').disableSubmitButtons(false);
            });

            // FOCUS ON THE MASKED INPUT
            telefone.focus(function(){
                // DISABLE THE VALIDATE
                $(form).data('bootstrapValidator').enableFieldValidators('telefone', false);
                // ENABLE THE SUBMIT BUTTON
                $(form).data('bootstrapValidator').disableSubmitButtons(false);
            }).blur(function(){ // BLUR ON THE MASKED INPUT
                // GET THE INPUT VALUE
                var value = telefone.val();
                // ENABLE THE VALIDATE 
                $(form).data('bootstrapValidator').enableFieldValidators('telefone', true);
                // CHECK IF THE VALUE IS EMPTY
                if(value != ""){
                    // CHANGE THE STATUS OF THE INPUT TO VALID 
                    $(form).data('bootstrapValidator').updateStatus('telefone', 'VALID')
                    // ACTIVE THE FLAG
                    alteredField = true;
                }else if (alteredField) { // IF THE INPUT WAS ALTERED BEFORE AND DON'T HAVE VALUE
                    // CHANGE THE STATUS OF THE INPUT TO INVALID
                    $(form).data('bootstrapValidator').updateStatus('telefone', 'INVALID')
                };
            });

        });

此代码修改了'bootstrapValidator'的标准行为,但这是我必须解决该bug的唯一方法。

我不了解性能问题,所以请修改和改进代码^^ 希望这有帮助^ _ ^

答案 6 :(得分:0)

我曾经遇到过同样的问题,我花了两个小时来制定适当的解决方案。最后,我编写了正确的代码。您可以使用它

对于邮政编码。

$.validator.addMethod("zipcode", function(postalcode, element) {
            //removes placeholder from string
            postalcode = postalcode.replace(/[^0-9]/g, "");
            //validates postalcode.
            return this.optional(element) || postalcode.match(/^\d{5}$|^\d{5}\-\d{4}$/);
        }, "Please specify a valid zip code");

如果要增加或减少邮政编码长度,请更改postalcode.match(/ ^ \ d {5} $ | ^ \ d {5}-\ d {4} $ /);根据您的要求编号。

对于手机,将使用相同的代码,但您只需要更改邮政编码,例如postalcode.match(/ ^ \ d {10} $ | ^ \ d {10}-\ d {9} $ /);

$.validator.addMethod("phone_length", function(phoneno, element) {
                //removes all special characters
                phoneno= phoneno.replace(/[^0-9]/g, "");
                return this.optional(element) || phoneno.match(/^\d{10}$|^\d{10}\-\d{9}$/);
            }, "Please enter a valid phone");

我希望这段代码对您有很大帮助。如果您想知道如何调用,只需在验证字段中添加 zipcode:true