web-dev-qa-db-fra.com

Ajout et suppression manuels des erreurs de validation dans le validateur jQuery

J'ai un formulaire de recherche et une grille basée sur les KO pour les résultats. Lorsque la recherche est effectuée, une validation côté serveur a lieu sur asp.net mvc, et si l'état du modèle n'est pas valide, il renvoie la liste des erreurs de modèle via JSON.

J'ai la validation jQuery déjà configurée et les validations par défaut (regex, requis, etc.) sont automatiquement mappées à l'aide du plugin jquery.unobtrusive. J'ai trouvé $.validate().showErrors({prop:error}) comme un moyen d'afficher dynamiquement les erreurs basées sur la réponse json du serveur, mais je pense que ce n'est pas la bonne façon de l'utiliser pour afficher les messages de validation du serveur, car le champ ne peut pas être réinitialisé par la suite ( input-validation-errorclass n'est pas supprimé).

J'ai besoin d'une méthode de travail pour définir et réinitialiser les erreurs sur le client, si elles existent dans $.validate.

Il y a un exemple avec mon problème sur jsFiddle: http://jsfiddle.net/goranobradovic/ughCm/

Pour le reproduire, cliquez sur ajouter une erreur, puis supprimez l'erreur, l'entrée reste rouge.

En effet, la fonction showErrors n'ajoute aucune règle déclenchée par la validation, le champ reste donc "valide" et il ne se trouve pas dans la liste elements() qui est utilisée dans resetForm pour supprimer input-validation-errorclass à partir de champs invalides.

Fondamentalement, je veux un moyen simple d'ajouter/supprimer une règle de validation avec un message personnalisé qui n'est jamais satisfait sur le client, pour éviter la soumission du formulaire lorsque je définis l'erreur manuellement et que je dois supprimer invalidclass après avoir supprimé l'erreur message.

37
Goran Obradovic

J'ai résolu cela en remplaçant la fonction showErrors dans le validateur jQuery par la mienne, qui est compatible avec les plages de validation générées de manière discrète, et en nettoyant les champs valides qui ont une classe non valide. Ce n'est pas une solution de contournement très agréable, mais cela fonctionne.

Voici jsfiddle avec la solution: http://jsfiddle.net/goranobradovic/ughCm/5/

MISE À JOUR: Comme le lien vers un site externe n'est pas la bonne réponse selon les directives du site, j'ajoute un exemple de code ici. Pour ceux qui connaissent déjà la validation jQuery, il suffit de regarder deux lignes de code dans la fonction showErrors. Je l'ai assigné au validateur avec validator.settings.showErrors = showErrors ;.

HTML:

<form id="experiment" action="/" method="post">

<fieldset>
  <legend></legend>
        <div class="editor-label">
          <label for="Email">Email</label>
        </div>
        <div class="editor-field">
<input data-val="true" data-val-email="&amp;#39;Email&amp;#39; not valid email address." data-val-required="&amp;#39;Email&amp;#39; is mandatory." id="Email" name="Email" type="text" value=""><span class="field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"></span>        
        </div>
        <div class="editor-label">
          <label for="FirstName">First name</label>
        </div>
        <div class="editor-field">
          <input class="text-box single-line" id="FirstName" name="FirstName" type="text" value="">
          <span class="field-validation-valid" data-valmsg-for="FirstName" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
          <label for="LastName">Last name</label>
        </div>
        <div class="editor-field">
          <input class="text-box single-line" id="LastName" name="LastName" type="text" value="">
          <span class="field-validation-valid" data-valmsg-for="LastName" data-valmsg-replace="true"></span>
        </div>   
</fieldset>
    <p>
        <button type="submit" class="save ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-secondary" value="Save" role="button" aria-disabled="false"><span class="ui-button-text">Save</span><span class="ui-button-icon-secondary ui-icon ui-icon-disk"></span></button>

    </p>
</form>
<br/>

<button id="add">Add error</button>
<button id="remove">Remove error</button>

<br/>
<br/>
Debug:
<div id="debug"></div>

JavaScript:

var validator = {};

function addError(e) {
    validator.showErrors({
        "FirstName": "test error"
    });
}

function removeError(e) {
    validator.showErrors({
        "FirstName": null
    });
    fixValidFieldStyles($("form"), validator);
}

$(document).ready(function() {
    var $form = $("#experiment");
    // prevent form submission
    $form.submit(function(e) {
        e.preventDefault();
        return false;
    });
    $("#add").click(addError);
    $("#remove").click(removeError);
    $("#debug").html("<h1>Validator properties:</h1>");
    validator = $form.validate();
    validator.settings.showErrors = showErrors;
    for (var i in validator) {
        var row = $("<span></span>").html(i).append("<br/>");
        $("#debug").append(row);
    }
});


function showErrors(errorMessage, errormap, errorlist) {
    var val = this;
    errormap.forEach(function(error, index) {
        val.settings.highlight.call(val, error.element, val.settings.errorClass, val.settings.validClass);
        $(error.element).siblings("span.field-validation-valid, span.field-validation-error").html($("<span></span>").html(error.message)).addClass("field-validation-error").removeClass("field-validation-valid").show();
    });
}

function fixValidFieldStyles($form, validator) {
    var errors = {};
    $form.find("input,select").each(function(index) {
        var name = $(this).attr("name");
        errors[name] = validator.errorsFor(name);
    });
    validator.showErrors(errors);
    var invalidFields = $form.find("." + validator.settings.errorClass);
    if (invalidFields.length) {
        invalidFields.each(function(index, field) {
            if ($(field).valid()) {
                $(field).removeClass(validator.settings.errorClass);
            }
        });
    }
}
23
Goran Obradovic

J'ai fait quelque chose d'un peu plus simple - essentiellement ajouté la possibilité d'enregistrer plus complètement l'erreur dans le validateur. J'ai ajouté ce qui suit à jquery.validate.js (sous showErrors):

addErrors: function (errors) {
        for (var i = 0; i < errors.length; i++) {
            this.errorList.Push({
                element: $(errors[i].element)[0],
                message: errors[i].message
            });
        }           
        this.showErrors();
    },

alors au lieu d'appeler form.validate (). showErrors () vous pouvez faire par exemple.

form.validate().addErrors([{
    element: $('#myinput'),
    message: 'A manual error message'
}]);

Enfin, parce que le formulaire peut ne pas avoir été marqué comme non valide lors de sa soumission, vous souhaiterez peut-être forcer une validation à la saisie ou similaire:

$('#myinput').one('keyup', function(){ $(this).valid(); });

(Remarque: ce n'est pas testé au combat, mais je suis sûr qu'au moins une solution se trouve de cette façon quelque part)

9
Gaz

J'ai fini par résoudre le problème d'une manière simple en nettoyant les erreurs, puis en affichant les nouvelles erreurs.

// get the form inside we are working - change selector to your form as needed
var $form = $("form");

// get validator object
var $validator = $form.validate();

// get errors that were created using jQuery.validate.unobtrusive
var $errors = $form.find(".field-validation-error span");

// trick unobtrusive to think the elements were succesfully validated
// this removes the validation messages
$errors.each(function(){ $validator.settings.success($(this)); })

// clear errors from validation
$validator.resetForm();

// Then show the errors
$.validator().showErrors({prop:error}
5
Amete Blessed