jQueryvalidation和屏蔽输入之间的冲突

我有一个表格,它使用jQuery Validate和Masked Input作为电话号码和美国邮政编码字段。

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

代码细节

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

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

重现步骤

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

  • 填写无效的邮政编码(比方说,三位数)
  • 远离田野。 Masked Input擦除输入(预期行为),jQuery Validate将其标记为无效,因为它是空白的(也是预期的)。
  • 返回邮政编码区并填写有效的5位数邮政编码。
  • 远离田野。 它仍被标记为无效。 这是出乎意料的

如果我填写一个9位数的邮编,则不会发生此问题。

假设

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

该假设得到以下事实的支持:如果随后重新validation表单,则zip字段将通过。 我这样做了两个方面:

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

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

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

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

更新:应用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版本。

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

因为我正在为zipcode定义我自己的validation器方法,所以我修改了它,以便在我从值中删除占位符后,如果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"); 

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

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

 $("[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插件validation,但是相同的元素由focusout事件上的validation器插件validation(在非ie浏览器上是模糊的包装器),在maskedinput的模糊之前调用。

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

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

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

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

诚挚

只需挂钩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. ie: // var $element = $(selector); // if($element.exists()) do something... $.fn.exists = function () { return this.length !== 0; } 

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

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

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

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

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

您执行绑定的顺序是否重要? 例如,两者之间是否存在差异

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

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

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

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

我的输入标记如下:

  

像这样的完整脚本:

 $(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的唯一方法。

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