form - jquery validate submithandler
La validaciĆ³n de jQuery no espera a que la validaciĆ³n remota se devuelva como verdadera (6)
$("#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());
Esto da como resultado verdadero, incluso si el valor no es válido. Veo que la validación finalmente falla y muestra el mensaje de error, pero el formulario aún se envía.
A partir de jQuery Validate 1.11.1 (y quizás incluso más antiguo), la respuesta aceptada no funciona. Además, no hay una respuesta fácil a esta pregunta y la solución requiere agregar un método de validación personalizado a la validación de jQuery.
En realidad, la respuesta fácil puede ser: no llame a valid()
manualmente si todo lo que desea hacer es enviar el formulario. Solo deja que el plugin Validar lo haga por ti. Internamente, esperará a que se completen todas las solicitudes asíncronas antes de permitir que se envíe el formulario. Este problema solo surge cuando se está verificando manualmente valid()
o element()
.
Sin embargo, hay muchas razones por las que puede necesitar hacer eso. Por ejemplo, la página en la que estoy trabajando necesita verificar la validez de un campo usando un validador remoto antes de habilitar el resto del formulario. Simplemente podría hacerlo a mano en lugar de usar jQuery Validation, pero eso es una duplicación de esfuerzos.
Entonces, ¿por qué configurar async: false
no funciona? Si establece async en falso, la solicitud se realizará de forma síncrona, sin embargo, el complemento no lo maneja correctamente. La función remote
interna siempre devuelve "pending"
que hará que la función valid()
devuelva true
incluso si la solicitud ya está completa y recibió una respuesta falsa. No verifica el valor de la respuesta ni muestra el error hasta más tarde.
La solución para hacer que valid()
y element()
comporten de forma sincrónica cuando se utiliza una devolución de llamada sincrónica es agregar un método de validación personalizado. Lo he intentado yo mismo, y parece funcionar bien. Solo puede copiar el código fuente de la validación remota regular y modificarlo para manejar las llamadas ajax sincrónicas, y ser sincrónico de manera predeterminada.
El código fuente de la función remota en v1.11.1 comienza en la línea 1112 de 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";
}
Observe que siempre devuelve "pendiente" incluso si la llamada ajax está completa.
Para solucionar este problema, haga las siguientes modificaciones:
- Mueva la declaración de la variable
valid
fuera de la llamada ajax y la función de éxito para hacer un cierre, y asígnele un valor predeterminado de "pendiente". - Cambie la antigua declaración de la variable
valid
a una asignación. - Devuelve la variable
valid
lugar de la constante "pendiente".
Aquí está el código completo para un complemento para el complemento. Simplemente guarde esto como un archivo js e inclúyalo en su página o plantilla después de incluir para la validación de 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.");
He probado esto con mi propia forma y funciona muy bien. Puedo probar la validez de mi elemento antes de habilitar el resto del formulario. Sin embargo, es probable que desee configurar onkeyup: false
para evitar que se realice una devolución de llamada sincrónica con cada pulsación de tecla. También me gusta usar onfocusout: false
.
Para usar esto, simplemente reemplaza "remoto" en tus configuraciones de validación con "synchronousRemote" en todos los lugares donde quieras usar esto. Por ejemplo:
$("#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
});
Al encontrarse con el mismo problema, parece que tiene configurada la llamada remota en sincrónico - async: false
De lo contrario, $("form").valid()
devolverá verdadero para la validación remota, por favor vea a continuación lo que uso
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"
} )
}
}
},
.....
Aquí hay una solución que se nos ocurrió en mi proyecto.
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
}
}
Esto aprovecha el hecho de que $ ("# form"). Validate (). PendingRequest siempre será> 0 siempre que haya una validación remota.
Nota: esto no funcionará con la configuración async: true
en la solicitud remota.
Debe detener el envío normal del navegador en caso de que la validación devuelva falso.
$("#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;
}
}
La forma más fácil de solucionar este problema (se informa aquí: https://github.com/jzaefferer/jquery-validation/issues/361 ) es verificar dos veces si el formulario es válido:
if (myForm.valid() && myForm.valid()) {
...
}
Establecer las reglas remotas en async:false
y comprobar la validez con valid()
realmente espera a que finalicen las llamadas, pero no se utilizan sus valores de retorno. Llamar a valid()
nuevamente los toma en cuenta.
Un poco feo pero funciona. Estoy usando jquery 2.1.0 y jquery-validation 1.11.1, BTW.
Sé que este es un parche pero lo he arreglado comprobando que el ajax actual está pendiente
$.active
llamada ajax actual por $.active
, le dará 0 si no se está ejecutando ajax
$(''#frmControlFamily #Identifier'').valid();
if ($.active == 0) {
// my save logic
}