jQuery 验证和屏蔽输入之间的冲突

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4399086/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 17:13:21  来源:igfitidea点击:

Conflict between jQuery Validate and Masked Input

jqueryvalidationmaskedinput

提问by Nathan Long

I've got a form that's using both jQuery Validateand Masked Inputfor phone number and US zip code fields.

我有一个表单,它对电话号码和美国邮政编码字段使用jQuery 验证屏蔽输入

For example, for a US zip code, Masked Input allows only numbers to be entered, and forces either the format "99999" or "99999-9999" (where 9 can be any number). The Validate rule requires the same. But in some cases, Validate marks a field as invalid when it should actually be valid.

例如,对于美国邮政编码,Masked Input 只允许输入数字,并强制采用“99999”或“99999-9999”格式(其中 9 可以是任何数字)。Validate 规则要求相同。但在某些情况下,Validate 会在字段实际有效时将其标记为无效。

Code Specifics

代码细节

The regex that jQuery Validate is using on the zip code field is ^\d{5}$|^\d{5}\-\d{4}$.

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

The mask I'm applying with Masked Input is .mask('99999?-9999')

我使用 Masked Input 应用的掩码是 .mask('99999?-9999')

Steps to reproduce

重现步骤

A conflict between them is produced when I do the following:

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

  • Fill out an invalid zip code (say, three digits)
  • Tab away from the field. Masked Input erases the input (expected behavior) and jQuery Validate marks it as invalid because it's blank (also expected).
  • Go back to the zip field and fill in a valid 5-digitzip.
  • Tab away from the field. It is still marked as invalid. This is unexpected.
  • 填写无效的邮政编码(例如,三位数)
  • 远离场地。屏蔽输入会擦除输入(预期行为)并且 jQuery Validate 将其标记为无效,因为它是空白的(也是预期的)。
  • 返回 zip 字段并填写有效的5 位zip。
  • 远离场地。它仍然被标记为无效。这是出乎意料的

This problem does nothappen if I fill out a 9-digit zip.

如果我填写 9 位 zip,则不会发生此问题。

Hypothesis

假设

I think this error is because in the case of the 5-digit zip, Masked Input has temporarily inserted "-____" to show the user that they can optionally enter a dash and four more digits. This is removed on blur, but before it's removed, the field is validated and fails, since underscores aren't permitted.

我认为这个错误是因为在 5 位 zip 的情况下,Masked Input 临时插入了“-____”以向用户显示他们可以选择输入一个破折号和另外四位数字。这在模糊时被删除,但在它被删除之前,该字段被验证并失败,因为下划线是不允许的。

This hypothesis is supported by the fact that, if the form is subsequently re-validated, the zip field will pass. I have done this two ways:

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

  • By submitting the form; all fields are re-validated when the submit button is clicked, the zip field passes, and the form submits.
  • By setting up a blurevent that re-validates that specific field. For example:

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

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

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

This can serve as a hacky solution, but isn't very satisfactory, because 1) the default settings already re-validate on blur, so this is repetitive, and 2) it requires additional code besides the normal Validate rules.

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

Has anybody else run into this issue? Do you have a more elegant solutionthan setting up an additional blur event listener?

有没有其他人遇到过这个问题?你有比设置额外的模糊事件监听器更优雅的解决方案吗?

Update: applying the hacky solution

更新:应用 hacky 解决方案

Even applying the hacky solution above doesn't work as nicely as I'd like. For instance, this doesn't work:

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

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

...nor does this:

...也不是这样:

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

...but this does:

...但这确实:

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

Since these elements are loaded by AJAX, the .eachversion has to be run each time a form section is loaded.

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

采纳答案by Adrian

I was actually looking for an answer to this exact question. Ended up figuring out a more reliable workaround.

我实际上正在寻找这个确切问题的答案。最终想出了一个更可靠的解决方法。

Since I am defining my own validator method for the zipcode I modified it so that it would remove the hyphen if the length of the zipcode was 6 after I removed the placeholder from the value.

由于我正在为邮政编码定义自己的验证器方法,因此我对其进行了修改,以便在从值中删除占位符后,如果邮政编码的长度为 6,它将删除连字符。

It looked like this:

它看起来像这样:

$.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");

So the postalcode I am validating will have the placeholders added by the input plugin and the hyphen removed if the zipcode that is entered only has 5 numerical digits (6 including the hyphen). So it will validate it properly.

因此,如果输入的邮政编码只有 5 个数字(包括连字符在内的 6 个),我正在验证的邮政编码将由输入插件添加的占位符和连字符删除。所以它会正确验证它。

回答by Erdogan Kurtur

I tried following solution, and it works like a charm.

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

$("[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]);
    }
  });

What triggers the problem is event ordering. When an element is masked, it is validated by maskedinput plugin on blur, but same element is validated by validator plugin on focusoutevent (which is a wrapper for blur on non-ie browsers) which is called before maskedinput's blur.

触发问题的是事件排序。当一个元素被屏蔽时,它由 maskedinput 插件 on 验证blur,但相同的元素由验证器插件在focusout事件(它是非 ie 浏览器上的模糊包装)验证,该事件在 maskedinput 的模糊之前调用。

In this situation input element has the value "(___) ___ __ __"when validator checks for the value. When code reaches maskedinput's blur event, plugin tests and clears the value since it is not a valid input.

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

Validation result may be different for each validation case. For instance requiredrules will pass with success since element has a value. non-required numberfields will fail even if we leave the input empty since a mask like "999"may be tested as 12_

每个验证案例的验证结果可能不同。例如,required规则将成功通过,因为元素有一个值。number即使我们将输入留空,非必填字段也会失败,因为像这样的掩码"999"可能会被测试为12_

the code above tests if form of masked input has validation attached to it, and recalls focusout event handler. Since our handler is attached as the latest, hopefully it will be called at last.

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

A warning, code simply copies behavior of validation plugin. It will probably work for a decade but may fail if validation plugin decides to do things different than now.

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

sincerely

真挚地

回答by Greg H

Simply hook in to the mask() function and append some additional logic to fire your own blur logic after the default mask's blur logic:

只需连接到 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));
    });
}

Also, you may notice the 'exists()' function. This is something I use a lot with my jQuery selectors:

此外,您可能会注意到 '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;
}

回答by Miguel Pinto

I had a similar problem and managed to solve it changing the default placeholder character to an empty string.

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

I was using a .mask('9?99');and was validating with a simple 'number' rule, and was having the same kind of conflict.

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

I changed the mask declaration to .mask('9?99',{placeholder:''});and... no more conflict. :)

我将掩码声明更改为.mask('9?99',{placeholder:''});和...不再发生冲突。:)

There's a possible problem in your case, because of the -in the zip code, which is always inserted in the form by the mask plugin. I think you can change the regexp to ^\d{5}\-$|^\d{5}\-\d{4}$(matching the dash in both cases) and it should validate then.

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

Anyway, you posted a while ago and probably don't need this anymore but perhaps it'll help someone else. :)

无论如何,您不久前发布了,可能不再需要它了,但也许它会帮助其他人。:)

回答by Jarrett Meyer

Does it matter the order that you do the binding? For example, is there a difference between

您进行绑定的顺序是否重要?例如,两者之间有区别吗?

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

and

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

I think that the bindings should fire in order.

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

回答by Luís Gustavo Batista

I tried some of the solutions but none worked for me, i'm using 'bootstrapValidator' (http://bootstrapvalidator.com/) and 'jquery.maskedinput' (http://digitalbush.com/projects/masked-input-plugin/) so if someone still have this problem, my solution was:

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

My input was marked like this:

我的输入被标记如下:

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

And the full script like this:

完整的脚本是这样的:

$(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')
                };
            });

        });

This code modifies the standard behavior of the 'bootstrapValidator', but was the only way that I gotta to solve the bug.

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

I don't know about performance issues, so please modify and improve the code ^^ Hope that this help ^_^

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

回答by Sumit Kumar Gupta

I had faced same issue and I spend two hours to make a proper solution. Finally, I made a proper code. You can use it

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

For ZIP code.

对于邮政编码。

$.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");

If you want to increase or decrease zip length then change postalcode.match(/^\d{5}$|^\d{5}-\d{4}$/); number according to your requirement.

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

For phone same code will be used but you need to change only numbers like postalcode.match(/^\d{10}$|^\d{10}-\d{9}$/);

对于电话,将使用相同的代码,但您只需要更改诸如 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");

I hope this code will help you a lot. If you want to know how to call then simply add zipcode:truein your validation field

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