Вот мой взлом "старой школы" ...
Ниже служебная функция, которая позволяет использовать «асинхронные» проверки с библиотекой «jquery.validate.js». Эта функция создает задержку между пользовательскими нажатиями клавиш, в противном случае функция проверки «validFunc» будет вызываться «все время», что в некоторых случаях не очень эффективно и особенно проблематично для функций, которые выполняют проверки на «серверной стороне» / «бэкэнде» (в основном ajax вызывает ). Таким образом, функция проверки validFunc вызывается только тогда, когда пользователь перестает печатать в течение определенного периода времени, что также позволяет выполнять проверку в реальном времени ("onkeyup": true
в настройках jqv), как это происходит во время ввода текста пользователем.
ВАЖНО: Проверки, включающие использование функции "jqvAsyncValid", всегда должны быть последними, чтобы избежать конфликтов с другими из-за асинхронности.
{
[...]
"rules": {
"field_name": {
"required": true,
"maxlength": 12,
"minlength": 4,
// NOTE: Validation involving the use of the "jqvAsyncValid" function. By Questor
"my_custom_ajax_validation": true
},
[...]
}
ОТВЕТНЫЙ КОД:
// NOTE: Adds the custom validation "my_custom_ajax_validation". By Questor
$.validator.addMethod("my_custom_ajax_validation", function (value, element) {
return jqvAsyncValid(element, "my_custom_ajax_validation", myValidationFunc, this);
}, "My error message!");
// NOTE: My validation function. By Questor
function myValidationFunc(domElement) {
if (someFuncWithAjaxCall(domElement.value) == "ALL_RIGHT!") {
return true;
} else {
return false;
}
}
// NOTE: Global "json" variable that stores the "status" ("isValid") and cycle control
// ("toCtrl") of asynchronously validated elements using the "jqvAsyncValid" function.
// By Questor
var jqvAsyncVState = {};
// NOTE: A utility function that allows the use of asynchronous validations with
// "jquery.validate.js". This function creates a delay between one user keystroke and
// another otherwise the validation function "validFunc" will be called "all time"
// which is not very performative in some circumstances and especially problematic
// for functions that perform validations on the serverside/backend (ajax calls basically).
// In this way the "validFunc" validation function is only called when the user stops
// typing for a certain period of time, which also allows a "realtime" validation
// as it occurs while the user is typing. By Questor
// [Ref .: https://jqueryvalidation.org/ ]
//. domElement - DOM element informed by jqv in the "addMethod" for the anonymous
// function;
//. asyncRuleNm - Validation name added via "addMethod";
//. validFunc - Function that will do the validation. Must have the signature
// "funcName(domElement)" returning "true" for valid and "false" for not;
//. jQValidInst - Instance of the current jqv within "addMethod". It is usually
// denoted by "this";
//. toInMsecs - "Timeout" in "milliseconds". If not informed the default will be
// 1500 milliseconds. Be careful not to use a very short timeout especially in
// "ajax" calls so as not to overload the serverside/backend.
// Eg.: `return jqvAsyncValid(element, "my_custom_ajax_validation", myValidationFunc, this);`.
function jqvAsyncValid(domElement, asyncRuleNm, validFunc, jQValidInst, toInMsecs) {
if (typeof toInMsecs === "undefined" || toInMsecs === "") {
toInMsecs = 1500;
}
var domEKey = jQValidInst.currentForm.id + domElement.name;
// NOTE: The validation messages need to be "displayed" and "hidden" manually
// as they are displayed asynchronously. By Questor
function errMsgHandler() {
if (jqvAsyncVState[domEKey]["isValid"]) {
// NOTE: If the current error message displayed on the element was that
// set in the rule added via "addMethod" then it should be removed since
// the element is valid. By Questor
// [Ref.: https://stackoverflow.com/a/11652922/3223785 ,
// https://stackoverflow.com/a/11952571/3223785 ]
if (jQValidInst.errorMap[domElement.name] == $.validator.messages[asyncRuleNm]) {
var iMsgNow = {};
iMsgNow[domElement.name] = "";
jQValidInst.showErrors(iMsgNow);
}
} else {
var iMsgNow = {};
// NOTE: If the element is invalid, get the message set by "addMethod"
// for current rule in "$.validator.messages" and show it. By Questor
iMsgNow[domElement.name] = $.validator.messages[asyncRuleNm];
jQValidInst.showErrors(iMsgNow);
}
}
if (!jqvAsyncVState.hasOwnProperty(domEKey)) {
// NOTE: Set the global json variable "jqvAsyncVState" the control attributes
// for the element to be asynchronously validated if it has not already been
// set. The key "domEKey" is formed by the "id" of the "form" that contains
// the element and the element's "name". By Questor
jqvAsyncVState[domEKey] = {
"toCtrl": null,
"isValid": undefined
};
}
var useOnKeyup = true;
// NOTE: The "onblur" event is required for "first validation" that only occurs
// in a "blur" event - this is inherent to jqv - and for situations where the
// user types very fast and triggers "tab" and the event "onkeyup" can not deal
// with it. By Questor
domElement.onblur = function (e) {
jqvAsyncVState[domEKey]["isValid"] = validFunc(domElement);
errMsgHandler();
useOnKeyup = false;
}
if (useOnKeyup) {
// NOTE: The strategy with the event "onkeyup" below was created to create
// a "delay" between a "keystroke" and another one otherwise the validation
// function "validFunc" will be called "all time" which is not very performative
// in some circumstances and especially problematic for functions that perform
// serverside/backend validations (ajax calls basically). In this way the
// "validFunc" validation function is only called when the user stops typing
// for a certain period of time ("toInMsecs"). By Questor
domElement.onkeyup = function (e) {
// NOTE: Clear the "toCtrl" if it has already been set. This will
// prevent the previous task from executing if it has been less than
// "toInMsecs". By Questor
clearTimeout(jqvAsyncVState[domEKey]["toCtrl"]);
// NOTE: Make a new "toCtrl" set to go off in "toInMsecs" ms. By Questor
jqvAsyncVState[domEKey]["toCtrl"] = setTimeout(function () {
jqvAsyncVState[domEKey]["isValid"] = validFunc(domElement);
errMsgHandler();
}, toInMsecs);
};
}
return jqvAsyncVState[domEKey]["isValid"];
}