La validation jQuery n’attend pas la validation à distance pour retourner true, considère que le formulaire est valide

$("#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()); 

Cela renvoie true, même si la valeur n’est pas valide. Je vois que la validation échoue finalement et affiche le message d’erreur mais le formulaire est toujours soumis.

À partir de jQuery Validate 1.11.1 (et peut-être même plus ancienne), la réponse acceptée ne fonctionne pas. En outre, il n’existe pas de réponse simple à cette question et la solution nécessite l’ajout d’une méthode de validation personnalisée à jQuery Validation.

En fait, la réponse la plus simple pourrait bien être la suivante: n’appelez pas valid() manuellement si vous ne voulez que soumettre le formulaire. Laissez simplement le plugin Validate le faire pour vous. En interne, il attendra que toutes les demandes asynchrones soient terminées avant de permettre la soumission du formulaire. Ce problème ne survient que lorsque vous vérifiez manuellement valid() ou element() .

Cependant, il y a de nombreuses raisons pour lesquelles vous pourriez avoir besoin de le faire. Par exemple, la page sur laquelle je travaille doit vérifier la validité d’un champ à l’aide d’un validateur distant avant d’activer le rest du formulaire. Je pourrais simplement le faire à la main au lieu d’utiliser la validation jQuery, mais c’est une duplication d’effort.

Alors, pourquoi la définition async: false ne fonctionne pas? Si vous définissez async sur false, la demande sera faite de manière synchrone, toutefois, le plug-in ne le gère pas correctement. La fonction remote interne renvoie toujours "pending" ce qui entraîne le retour de la fonction valid() à true même si la requête est déjà terminée et a reçu une fausse réponse! Il ne vérifie pas la valeur de la réponse et n’affiche l’erreur que plus tard.

La solution pour que valid() et element() se comportent de manière synchrone lors de l’utilisation d’un rappel synchrone consiste à append une méthode de validation personnalisée. Je l’ai essayé moi-même et cela semble bien fonctionner. Vous pouvez simplement copier le code source à partir de la validation à distance normale et le modifier pour gérer les appels ajax synchrones, et être synchrone par défaut.

Le code source de la fonction distante dans la version 1.1.1 commence à la ligne 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 === "ssortingng" && {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"; } 

Remarquez qu’il retourne toujours “en attente” même si l’appel ajax est terminé.

Pour résoudre ce problème, apportez les modifications suivantes:

  1. Déplacez la déclaration de la variable valid dehors de l’appel ajax et de la fonction success pour effectuer une fermeture et atsortingbuez-lui une valeur par défaut de “en attente”.
  2. Remplacez l’ancienne déclaration de la variable valid par une affectation.
  3. Renvoie la variable valid à la place de la constante “en attente”.

Voici le code complet pour un plugin au plugin. Enregistrez simplement ceci en tant que fichier js et incluez-le dans votre page ou modèle après la validation d’inclusion pour 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 === "ssortingng" && { 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."); 

J’ai testé cela avec ma propre forme et cela fonctionne très bien. Je peux tester la validité de mon élément avant d’activer le rest du formulaire. Cependant, vous souhaiterez probablement définir onkeyup: false pour empêcher l’exécution d’un rappel synchrone à chaque pression sur une touche. J’aime aussi utiliser onfocusout: false .

Pour l’utiliser, il suffit de remplacer “remote” dans vos parameters de validation par “synchronousRemote” partout où vous souhaitez l’utiliser. Par exemple:

 $("#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 }); 

Bumped dans le même problème, il semble que vous avez défini l’appel synchrone à distance – async: false

Sinon, $("form").valid() retournera true pour la validation à distance, veuillez voir ci-dessous ce que j’utilise

 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.ssortingngify( { Name: "UNIQUE NAME" } ) } } }, ..... 

Voici une solution que nous avons trouvée sur mon projet.

 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 } } 

Cela tire parti du fait que $ (“# form”). Validate (). WaitingRequest sera toujours> 0 chaque fois qu’il y aura une validation à distance.

Remarque: cela ne fonctionnera pas avec la définition de async: true dans la demande distante.

Le moyen le plus simple de résoudre ce problème (signalé ici: https://github.com/jzaefferer/jquery-validation/issues/361 ) consiste à vérifier deux fois si le formulaire est valide:

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

Définir les règles distantes sur async:false et vérifier la validité à l’aide de valid() attend la fin des appels, mais leurs valeurs de retour ne sont pas utilisées. L’appel de valid() prend à nouveau en compte.

Un peu moche mais ça marche. J’utilise jquery 2.1.0 et jquery-validation 1.11.1, BTW.

Vous devez arrêter la soumission normale du navigateur au cas où la validation renverrait 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; } } 

Je sais qu’il s’agit d’un correctif mais je l’ai corrigé en vérifiant que le fichier ajax actuel est en attente

Je vérifie l’appel ajax actuel par $.active , il vous donnera 0 si ajax n’est pas en cours d’exécution

 $('#frmControlFamily #Identifier').valid(); if ($.active == 0) { // my save logic }