Проверка JQuery не ожидает удаленной проверки, чтобы вернуть true, считает форму действительной - PullRequest
21 голосов
/ 30 августа 2011
$("#new_component_form").validate({
  errorClass: 'input-error',
  rules : {
    "comp_data[account_name]" : {
      required: true,
      remote: {
        url: "/validate",
        data: {
          provider: 'twitter'
        }
      }
    }
  },
  onsubmit: true,
  onfocusout: false,
  onkeyup: false,
  onclick: false
});



 $("#new_component_form").submit(function(){
    console.log($(this).valid());

Это выводит true, даже если значение недопустимо. Я вижу, что валидация в итоге не удалась и я вижу сообщение об ошибке, но форма все еще отправлена

Ответы [ 7 ]

28 голосов
/ 23 декабря 2013

Начиная с jQuery Validate 1.11.1 (и, возможно, даже старше) принятый ответ не работает. Кроме того, нет простого ответа на этот вопрос, и решение требует добавления пользовательского метода проверки в jQuery Validation.

На самом деле, простой ответ может быть следующим: не звоните valid() вручную, если все, что вы хотите сделать, это отправить форму. Просто позвольте плагину Validate сделать это за вас. Внутри он будет ожидать завершения всех асинхронных запросов, прежде чем разрешить отправку формы. Эта проблема возникает только при ручной проверке valid() или element().

Однако существует множество причин, по которым вам может понадобиться это сделать. Например, страница, над которой я работаю, должна проверить правильность поля с помощью удаленного валидатора, прежде чем активировать оставшуюся часть формы. Я мог бы просто сделать это вручную вместо использования JQuery Validation, но это дублирование усилий.

Итак, почему настройка async: false не работает? Если для async установлено значение false, запрос будет выполняться синхронно, однако плагин не будет правильно обрабатывать это. Внутренняя функция remote всегда возвращает "pending", в результате чего функция valid() возвращает true , даже если запрос уже выполнен и получил ложный ответ! Он не проверяет значение ответа или покажите ошибку позже.

Решением заставить valid() и element() вести себя синхронно при использовании синхронного обратного вызова является добавление пользовательского метода проверки. Я попробовал это сам, и, кажется, работает нормально. Вы можете просто скопировать исходный код из обычной удаленной проверки и изменить его для обработки синхронных вызовов ajax и быть синхронным по умолчанию.

Исходный код удаленной функции в v1.11.1 начинается в строке 1112 файла jquery.validate.js:

remote: function( value, element, param ) {
    if ( this.optional(element) ) {
        return "dependency-mismatch";
    }

    var previous = this.previousValue(element);
    if (!this.settings.messages[element.name] ) {
        this.settings.messages[element.name] = {};
    }
    previous.originalMessage = this.settings.messages[element.name].remote;
    this.settings.messages[element.name].remote = previous.message;

    param = typeof param === "string" && {url:param} || param;

    if ( previous.old === value ) {
        return previous.valid;
    }

    previous.old = value;
    var validator = this;
    this.startRequest(element);
    var data = {};
    data[element.name] = value;
    $.ajax($.extend(true, {
        url: param,
        mode: "abort",
        port: "validate" + element.name,
        dataType: "json",
        data: data,
        success: function( response ) {
            validator.settings.messages[element.name].remote = previous.originalMessage;
            var valid = response === true || response === "true";
            if ( valid ) {
                var submitted = validator.formSubmitted;
                validator.prepareElement(element);
                validator.formSubmitted = submitted;
                validator.successList.push(element);
                delete validator.invalid[element.name];
                validator.showErrors();
            } else {
                var errors = {};
                var message = response || validator.defaultMessage( element, "remote" );
                errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
                validator.invalid[element.name] = true;
                validator.showErrors(errors);
            }
            previous.valid = valid;
            validator.stopRequest(element, valid);
        }
    }, param));
    return "pending";
}

Обратите внимание, что он всегда возвращает «в ожидании», даже если вызов ajax завершен.

Чтобы исправить эту проблему, внесите следующие изменения:

  1. Переместите объявление переменной valid за пределы вызова ajax и функции success, чтобы сделать замыкание, и присвойте ему значение по умолчанию «pending».
  2. Заменить старое объявление переменной valid на присвоение.
  3. Возвращает переменную valid вместо постоянной "pending".

Вот полный код для плагина к плагину. Просто сохраните это как файл js и включите его в свою страницу или шаблон после включения для проверки jQuery:

//Created for jQuery Validation 1.11.1
$.validator.addMethod("synchronousRemote", function (value, element, param) {
    if (this.optional(element)) {
        return "dependency-mismatch";
    }

    var previous = this.previousValue(element);
    if (!this.settings.messages[element.name]) {
        this.settings.messages[element.name] = {};
    }
    previous.originalMessage = this.settings.messages[element.name].remote;
    this.settings.messages[element.name].remote = previous.message;

    param = typeof param === "string" && { url: param } || param;

    if (previous.old === value) {
        return previous.valid;
    }

    previous.old = value;
    var validator = this;
    this.startRequest(element);
    var data = {};
    data[element.name] = value;
    var valid = "pending";
    $.ajax($.extend(true, {
        url: param,
        async: false,
        mode: "abort",
        port: "validate" + element.name,
        dataType: "json",
        data: data,
        success: function (response) {
            validator.settings.messages[element.name].remote = previous.originalMessage;
            valid = response === true || response === "true";
            if (valid) {
                var submitted = validator.formSubmitted;
                validator.prepareElement(element);
                validator.formSubmitted = submitted;
                validator.successList.push(element);
                delete validator.invalid[element.name];
                validator.showErrors();
            } else {
                var errors = {};
                var message = response || validator.defaultMessage(element, "remote");
                errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
                validator.invalid[element.name] = true;
                validator.showErrors(errors);
            }
            previous.valid = valid;
            validator.stopRequest(element, valid);
        }
    }, param));
    return valid;
}, "Please fix this field.");

Я проверил это с моей собственной формой, и она прекрасно работает. Я могу проверить свой элемент на достоверность, прежде чем активировать оставшуюся часть формы. Однако вы, вероятно, захотите установить onkeyup: false, чтобы предотвратить выполнение синхронного обратного вызова при каждом нажатии клавиши. Мне также нравится использовать onfocusout: false.

Чтобы использовать это, просто замените «remote» в настройках проверки на «synchronousRemote» везде, где вы хотите это использовать. Например:

$("#someForm").validate({
    rules: {
        someField: {
            required: true,
            synchronousRemote: {
                    url: "/SomePath/ValidateSomeField"
                    //notice that async: false need not be specified. It's the default.
            }
        }
    },
    messages: {
        someField: {
            required: "SomeField is required.",
            synchronousRemote: "SomeField does not exist."
        }
    },
    onkeyup: false,
    onfocusout: false
});
6 голосов
/ 13 мая 2015

Вот решение, которое мы придумали в моем проекте.

var validPendingTimeout;

function doSomethingWithValid() {
  var isValid = $("#form").valid();
  var isPending = $("#form").validate().pendingRequest !== 0;

  if (isPending) {
    if (typeof validPendingTimeout !== "undefined") {
      clearTimeout(validPendingTimeout);
    }
    validPendingTimeout = setTimeout(doSomethingWithValid, 200);
  }

  if (isValid && !isPending) {
    // do something when valid and not pending
  } else {
    // do something else when not valid or pending
  }
}

При этом используется тот факт, что $ ("# form"). Validate (). PendingRequest всегда будет> 0 при удаленной проверке.

Примечание: это не будет работать с настройкой async: true в удаленном запросе.

6 голосов
/ 05 сентября 2014

Самый простой способ решить эту проблему (сообщается здесь: https://github.com/jzaefferer/jquery-validation/issues/361) - дважды проверить правильность формы:

if (myForm.valid() && myForm.valid()) {
    ...
}

Установка для удаленных правил значения async:false и проверкадля правильности использования valid() фактически ожидает завершения вызовов, но их возвращаемые значения не используются. Повторный вызов valid() учитывает их.

Немного некрасиво, но это работает. Я использую jquery2.1.0 и jquery-validation 1.11.1, кстати.

6 голосов
/ 19 октября 2012

Столкнулся с той же проблемой, похоже, что вы установили удаленный вызов на синхронный - async: false

В противном случае $("form").valid() вернет true для удаленной проверки, смотрите ниже то, что я использую

rules: {
    NameToValidate: {
        required: true,
        remote: function()
        {
            return {
            type: "POST",
            async: false,
            url: "www.mysite.com/JSONStuff",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: JSON.stringify( {
                Name: "UNIQUE NAME"
            } )
        }
    }
},
.....
0 голосов
/ 14 февраля 2019

Вы можете проверить форму дважды или проверить завершение текущего вызова ajax.

if (myForm.valid() && myForm.valid()) {

}

или

if ($.active == 0) {

}

До сих пор лучшее решение, которое я нашел, упоминалось в верхней частиэтой темы.https://stackoverflow.com/a/20750164/11064080

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

0 голосов
/ 04 июля 2018

Я знаю, что это патч, но я исправил его, проверив текущий ожидающий ajax

Я проверяю текущий вызов ajax с помощью $.active, он выдаст 0, если не запущен ajax

$('#frmControlFamily #Identifier').valid();            
if ($.active == 0) {
    // my save logic
}
0 голосов
/ 30 августа 2011

Вы должны прекратить обычную отправку браузера, если проверка вернет false.

$("#new_component_form").submit(function() {
    if ($(this).valid())) {
        console.log("I'm a valid form!");
    } else {
        console.log("I'm NOT a valid form!");
        //Stop the normal submit of the browser
        return false;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...