Подтвердить что ты не робот

Конфликт между jQuery Validate и Masked Input

У меня есть форма, которая использует jQuery Validate и Masked Введите для номера телефона и полей почтового индекса США.

Например, для американского почтового индекса Masked Input позволяет вводить только цифры и заставляет либо формат "99999", либо "99999-9999" (где 9 может быть любым числом). Правило Validate требует того же. Но в некоторых случаях Validate помещает поле как недопустимое, когда оно действительно действительно.

Спецификация кода

Регулярное выражение, которое jQuery Validate использует в поле почтового индекса, ^\d{5}$|^\d{5}\-\d{4}$.

Маска, которую я применяю с Masked Input, .mask('99999?-9999')

Шаги по воспроизведению

Конфликт между ними возникает, когда я делаю следующее:

  • Заполните недопустимый почтовый индекс (скажем, три цифры)
  • Вкладка вдали от поля. Masked Input стирает ввод (ожидаемое поведение), а jQuery Validate отмечает его как недопустимый, поскольку он пуст (также ожидается).
  • Вернитесь в поле zip и заполните действительный 5-значный почтовый индекс.
  • Вкладка вдали от поля. Он по-прежнему отмечен как недопустимый. Это неожиданно.

Эта проблема делает не, если я заполняю 9-значный почтовый индекс.

Гипотезы

Я думаю, что эта ошибка связана с тем, что в случае 5-значного почтового индекса Masked Input временно вставил "-____", чтобы показать пользователю, что они могут дополнительно ввести тире и еще четыре цифры. Это удаляется при размытии, но перед его удалением поле проверяется и не выполняется, поскольку символы подчеркивания не разрешены.

Эта гипотеза подтверждается тем фактом, что, если форма впоследствии будет повторно проверена, пройдет почтовое поле. Я сделал это двумя способами:

  • Отправляя форму; все поля повторно проверяются при нажатии кнопки отправки, заполняется почтовое поле и форма отправляется.
  • Установив событие blur, которое повторно проверяет это конкретное поле. Например:

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

Это может быть хакерским решением, но не очень удовлетворительно, потому что 1) настройки по умолчанию уже повторно проверяются при размытии, поэтому это повторяется и 2) для этого требуется дополнительный код кроме обычных правил Validate.

Кто-нибудь еще сталкивается с этой проблемой? У вас есть более элегантное решение, чем настройка дополнительного прослушивателя событий размытия?

Обновление: применение хакерского решения

Даже применение взломанного решения выше не так хорошо, как хотелось бы. Например, это не работает:

$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 должна запускаться каждый раз, когда загружается раздел формы.

4b9b3361

Ответ 1

Я действительно искал ответ на этот точный вопрос. Закончилось выяснение более надежного обходного пути.

Поскольку я определяю свой собственный метод валидатора для zipcode, я его модифицировал, чтобы удалить дефис, если длина zipcode равна 6 после того, как я удалил placeholder из значения.

Это выглядело так:

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

Таким образом, почтовый ящик, который я проверяю, будет иметь заполнители, добавленные плагином ввода, и дефис удаляется, если введенный zipcode имеет только 5 числовых цифр (6, включая дефис). Поэтому он будет правильно проверять его.

Ответ 2

Я пробовал следующее решение, и оно работает как шарм.

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

Что вызывает проблему, это упорядочение событий. Когда элемент замаскирован, он проверяется плагином maskedinput на blur, но тот же элемент проверяется плагином-валидатором на событии focusout (который является оберткой для размытия на не-точечных браузерах), который вызывается до маскировки размытия.

В этой ситуации элемент ввода имеет значение "(___) ___ __ __", когда валидатор проверяет значение. Когда код достигает события maskedinput blur, плагин проверяет и очищает значение, поскольку это не допустимый ввод.

Результат проверки может отличаться для каждого случая проверки. Например, правила required пройдут успешно, так как элемент имеет значение. необязательные поля number не удастся, даже если мы оставим вход пустым, так как маска типа "999" может быть протестирована как 12_

код выше тестов, если форма маскированного ввода имеет прикрепленную к нему проверку и вызывает обработчик события фокуса. Поскольку наш обработчик присоединен как последний, мы надеемся, он будет называться наконец.

Предупреждение, код просто копирует поведение плагина проверки. Вероятно, это будет работать десятилетие, но может потерпеть неудачу, если плагин validation решит сделать что-то по-другому, чем сейчас.

искренне

Ответ 3

Просто подключитесь к функции 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;
}

Ответ 4

У меня была аналогичная проблема, и мне удалось ее решить, изменив символ-заполнитель по умолчанию на пустую строку.

Я использовал .mask('9?99'); и проверял с помощью простого правила "числа" и имел тот же конфликт.

Я изменил объявление маски на .mask('9?99',{placeholder:''}); и... больше не конфликтует.:)

В вашем случае может возникнуть проблема из-за - в почтовом индексе, который всегда вставляется в форму плагином mask. Я думаю, вы можете изменить regexp на ^\d{5}\-$|^\d{5}\-\d{4}$ (соответствующий тире в обоих случаях), и он должен подтвердить это.

В любом случае, вы опубликовали какое-то время и, вероятно, больше не нуждаетесь в этом, но, возможно, это поможет кому-то другому.:)

Ответ 5

Имеет ли значение порядок выполнения привязки? Например, существует ли разница между

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

и

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

Я думаю, что привязки должны срабатывать по порядку.

Ответ 6

Я пробовал некоторые из решений, но никто не работал у меня, я использую "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>

И полный script следующий:

$(document).ready(function() {
   var telefone = $('#telefone'), //THAT MY INPUT WITH MASK
       form = telefone.parents("form"), //THAT MY FORM WITH THE VALIDATE
       alteredField = false; //THAT 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", но это единственный способ, которым я должен решить проблему.

Я не знаю о проблемах с производительностью, поэтому, пожалуйста, измените и улучшите код ^^ Надеюсь, что эта помощь ^ _ ^