Ответ 1
Как и в случае jQuery Validate 1.11.1 (и, возможно, даже старше), принятый ответ не работает. Кроме того, на этот вопрос нет простого ответа, и для решения требуется добавить специальный метод проверки для проверки jQuery.
На самом деле простой ответ может быть просто: Не называть valid()
вручную, если все, что вы хотите сделать, это отправить форму. Просто пусть плагин Validate сделает это за вас. Внутри он будет ожидать завершения всех асинхронных запросов, прежде чем разрешить отправку формы. Эта проблема возникает только при ручной проверке valid()
или element()
.
Однако есть много причин, по которым вам может понадобиться это сделать. Например, на странице, на которой я работаю, необходимо проверить правильность поля с помощью удаленного валидатора, прежде чем включать остальную часть формы. Я мог бы просто сделать это вручную, вместо использования проверки jQuery, но это дублирование усилий.
Итак, почему настройка 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 завершен.
Чтобы устранить эту проблему, внесите следующие изменения:
- Переместить объявление переменной
valid
за пределы вызова ajax и функцию успеха, чтобы сделать закрытие, и присвоить ему значение по умолчанию "pending". - Измените старое объявление переменной
valid
на назначение. - Вернуть переменную
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 the default.
}
}
},
messages: {
someField: {
required: "SomeField is required.",
synchronousRemote: "SomeField does not exist."
}
},
onkeyup: false,
onfocusout: false
});