Конфликт между проверкой jQuery и замаскированным вводом - PullRequest
25 голосов
/ 09 декабря 2010

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

Например, для почтового индекса США Маскированный ввод позволяет вводить только цифры и вводит формат «99999» или «99999-9999» (где 9 может быть любым числом). Правило проверки требует того же. Но в некоторых случаях Validate помечает поле как недействительное, если оно действительно должно быть действительным.

Особенности кода

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

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

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

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

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

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

1039 * Гипотеза * Я думаю, что эта ошибка связана с тем, что в случае 5-значного почтового индекса Маскированный ввод временно вставил «-____», чтобы показать пользователю, что он может дополнительно ввести тире и еще четыре цифры. Это удаляется при размытии, но перед тем, как оно будет удалено, поле проверяется и завершается ошибкой, поскольку подчеркивание не допускается. Эта гипотеза подтверждается тем фактом, что, если форма будет впоследствии повторно проверена, поле zip пройдет. Я сделал это двумя способами: Отправив форму; все поля повторно проверяются при нажатии кнопки отправки, поле zip проходит и отправляется форма. Установив событие blur, которое повторно проверяет это конкретное поле. Например: $ ("# zipcode"). Blur (function () {$ (this) .closest ('form'). Validate (). Element ($ (this));}); Это может служить хакерским решением , но не очень удовлетворительно, потому что 1) настройки по умолчанию уже повторно проверяются на размытие, так что это повторяется, и 2) кроме него требуется дополнительный код нормальные правила валидации. Кто-нибудь еще сталкивался с этой проблемой? Есть ли у вас более элегантное решение , чем настройка дополнительного слушателя событий размытия? Обновление: применение хакерского решения

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

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

Ответы [ 6 ]

11 голосов
/ 14 марта 2012

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

$("[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, но тот же элемент проверяется плагином validator на событии focusout (которое является оболочкой для размытия в браузерах, отличных от ie), которое вызывается до размытия maskedinput.

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

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

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

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

искренно

9 голосов
/ 02 февраля 2011

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

Поскольку я определяю свой собственный метод проверки для почтового индекса, я изменил его так, чтобы он удалял дефис, если длина почтового индекса была 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 цифр (6, включая дефис). Так что это будет правильно проверять.

7 голосов
/ 06 декабря 2012

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

Кроме того, вы можете заметить функцию 'exist ()'. Это то, что я часто использую с моими селекторами 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;
}
5 голосов
/ 19 августа 2011

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

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

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

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

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

1 голос
/ 09 декабря 2010

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

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

и

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

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

0 голосов
/ 12 ноября 2014

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

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

...