jquery.validate.unobtrusive ne fonctionne pas avec les éléments injectés dynamiques

99

Je travaille avec ASP.Net MVC3, le moyen le plus simple d'utiliser la validation client serait d'activer le jquery.validate.unobtrusive. Tout fonctionne bien, pour les éléments provenant directement du serveur.

Mais quand j'essaye d'injecter de nouvelles «entrées» avec javascript, et je savais que je devais appeler $.validator.unobtrusive.parse()pour relier les validations. Mais encore, tous ces champs injectés dynamiques ne fonctionnent pas.

Pire encore, j'essaie de lier manuellement en utilisant jquery.validateet cela ne fonctionne pas non plus. Des pensées?

xandy
la source
1
Si vous êtes venu ici depuis Google, vous recherchez probablement la réponse de @Sundara Prabu, car les autres qui sont massivement votées sont anciennes.
The Muffin Man

Réponses:

65

J'ai créé une extension pour la bibliothèque jquery.validate.unobtrusive qui a résolu ce problème pour ma situation - cela pourrait être intéressant.

http://xhalent.wordpress.com/2011/01/24/applying-unobtrusive-validation-to-dynamic-content/

Xhalent
la source
Je pense que je devrais voter pour votre réponse comme étant la bonne. BTW, votre bibliothèque fonctionne-t-elle avec le dernier MVC RC? ou ils ont juste corrigé ça?
xandy
1
Lorsque vous utilisez le code lié ci-dessus, assurez-vous de le mettre à jour pour inclure le code dans les commentaires, sinon il peut casser. Plus précisément, modifiez les deux lignes de sélection pour double guillemet l'identifiant.
Ryan O'Neill le
1
J'ai finalement pu faire fonctionner cela pour mon scénario après quelques débogages. Il semble qu'il ne devrait pas passer dans un sélecteur d'entrée, mais le parent de l'entrée ou le formulaire, en raison de l'appel à $.validator.unobtrusive.parse(). En outre, il semble uniquement ajouter de nouvelles règles, mais pas prendre les mises à jour des règles existantes?
lambinator
5
Cette réponse doit contenir au moins les os d'ours du blog. Les réponses aux liens uniquement sont généralement hors sujet pour SO
Liam
8
Bien que cette réponse ait plus de 3 ans, il serait extrêmement utile que vous puissiez publier les parties essentielles de la réponse ici, sur ce site, ou votre publication risque d'être supprimée Voir la FAQ où elle mentionne des réponses qui sont `` à peine plus qu'un lien ». Vous pouvez toujours inclure le lien si vous le souhaitez, mais uniquement en tant que «référence». La réponse doit être autonome sans avoir besoin du lien.
Taryn
159

J'ai essayé l'approche de Xhalent mais malheureusement cela ne fonctionnait pas pour moi. L'approche de Robin a fonctionné et n'a pas fonctionné. Cela fonctionnait très bien pour les éléments ajoutés dynamiquement, mais si vous essayiez d'utiliser JQuery pour supprimer tous les attributs de validation et les étendues du DOM, la bibliothèque de validation essaierait toujours de les valider.

Cependant, si vous supprimez les données "unobtrusiveValidation" du formulaire en plus de "validationData", cela fonctionnait comme un charme pour ajouter et supprimer dynamiquement des éléments que vous souhaitez valider ou non.

$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
vigueur
la source
2
Xhalent n'a pas fonctionné pour moi au début non plus, puis j'ai remarqué que l'analyse devrait être passée un conteneur pour les nouveaux éléments, PAS les éléments eux-mêmes - une solution rapide serait de passer le formulaire entier au lieu du ou des éléments - puis il a fonctionné comme un charme.
Per Hornshøj-Schierbeck
1
une idée pourquoi il dit validatorn'est pas défini? J'ai à la fois la validation et la validation.unobtrusive référencée. La validation fonctionne jusqu'à ce que j'appelle ces codes
Shawn Mclean
4
Merci. Cela fonctionne pour le contenu ajouté à la page dans les vues partielles ASP.MVC ajoutées via un appel AJAX.
Maksym Kozlenko
Merci cela a aidé. Mais je suis confronté à un problème où j'utilise des accordéons sur la page et si l'accordéon est réduit, il ne déclenche pas les validations. Comment puis-je réparer cela? Je sais que si j'étais allé pour le plugin de validation jquery normal au lieu de MVC3 discret, je devais dire$('#form').validate({ignore: ""})
parsh
1
Cela a fonctionné pour moi en PHP. ajouter simplement ces informations car chaque commentaire pointe vers .NET MVC. : P
finnTheHumin
42

En fait, j'aime beaucoup la simplicité de la solution @viggity et @Robins, alors je l'ai transformée en un petit plugin rapide:

(function ($) {

    $.fn.updateValidation = function () {
        var $this = $(this);
        var form = $this.closest("form")
            .removeData("validator")
            .removeData("unobtrusiveValidation");

        $.validator.unobtrusive.parse(form);

        return $this;
    };
})(jQuery);

Exemple d'utilisation:

$("#DischargeOutcomeNumberOfVisits")
    .attr("data-val-range-min", this.checked ? "1" : "2")
    .updateValidation();
lambinator
la source
remplace $ .validator.unobtrusive.parse ("#" + form.attr ("id")); avec $ .validator.unobtrusive.parse (formulaire);
Softlion
vous pouvez également supprimer en toute sécurité .first () car le plus proche ne renvoie qu'un seul élément.
Softlion
Bien, j'aime cette approche simple
nixon
Fonctionne à merveille pour ajouter et supprimer des attributs data-val
Julian Dormon
33

J'ai le même problème. J'ai découvert qu'il n'était pas possible d'appeler deux fois $ .validator.unobtrusive.parse () sur le même formulaire. Lors du chargement initial du formulaire à partir du serveur, le formulaire est analysé automatiquement par la bibliothèque discrète. Lorsque vous ajoutez dynamiquement un élément d'entrée au formulaire et que vous appelez à nouveau $ .validator.unobtrusive.parse (), cela ne fonctionnera pas. Il en va de même pour parseElement ().

La bibliothèque discrète appelle la méthode validate du plugin jquery validate pour définir toutes les règles et tous les messages. Le problème est que, lorsqu'il est appelé à nouveau, le plugin ne met pas à jour le nouvel ensemble de règles qu'il a donné.

J'ai trouvé une solution grossière: avant d'appeler la méthode parse sur la lib non obstructive, je jette le validateur de formulaire:

$('yourForm').removeData("validator");

Désormais, lorsque la méthode validate est appelée par la bibliothèque discrète, toutes les règles et tous les messages sont recréés, y compris les entrées ajoutées dynamiquement.

J'espère que cela t'aides

Robin van der Knaap
la source
Mérite un +1 - c'est une solution grossière comme vous l'avez dit vous-même, mais c'est assez clair ce qu'elle fait et dans quel état il vous reste par la suite
Per Hornshøj-Schierbeck
2
Du blog de Brad Wilsons: "Vous pouvez également appeler la fonction jQuery.validator.unobtrusive.parseElement () pour analyser un seul élément HTML." De l'aide?
jamesfm
@Per Hornshøj-Schierbeck: @Robin van der Knaap: J'ai passé les 2-3 dernières heures à comprendre ça !! Quoi qu'il en soit, cela a fonctionné à merveille. Crude me donne l'impression que je ne devrais pas l'utiliser - pourquoi ne voudrais-je pas faire ça?
KTF
2
La solution est un peu grossière car tous les validateurs sont supprimés et rétablis, y compris le validateur ajouté dynamiquement. Ce serait mieux si seul le validateur ajouté dynamiquement était mis à jour. @Xhalent fournit une solution plus propre dans sa réponse, mais fondamentalement, la bibliothèque discrète de MS devrait être mise à jour pour ce scénario.
Robin van der Knaap
9

J'utilise MVC 4 et JQuery 1.8, il semble que le morceau de code suivant est nécessaire pour permettre à Jquery de valider le contenu injecté dynamiquement via Ajax ou Jquery dans le DOM.

J'ai créé une fonction modulaire qui accepte l'objet Jquery de l'élément nouvellement ajouté. Si vous avez cloné une nouvelle table avec id en tblContactsutilisant Jquery en cliquant sur un bouton, incluez la fonction ci-dessous dans votre fichier js

function fnValidateDynamicContent(element) {
    var currForm = element.closest("form");
    currForm.removeData("validator");
    currForm.removeData("unobtrusiveValidation");
    $.validator.unobtrusive.parse(currForm);
    currForm.validate(); // This line is important and added for client side validation to trigger, without this it didn't fire client side errors.
}

et appelez-le comme ceci:

fnValidateDynamicContent("#tblContacts")
Sundara Prabu
la source
currform.validate (); devrait en fait être currForm.validate (); (faute de frappe). Merci pour le partage, cela a fonctionné pour moi
John Mc
1
@JohnMc a corrigé la faute de frappe maintenant
Sundara Prabu
C'est le seul qui a fonctionné pour moi (mvc 4 et jquery 1.10)
The Muffin Man
4

Pourquoi ne pas utiliser la fonction rules directement à partir du doc ​​de validation jquery. Comme ça:

$('#newField0').rules('add', {
    required: true,
    minlength: 2
});
//use Html.ValidationMessage will renders a span element, unobtrusive need it to display errors
$('@Html.ValidationMessage("newField0")').insertAfter('#newField0');
zhangfx
la source
2

En prenant la solution de Xhalent marquée comme réponse ci-dessus, je l'ai un peu développé.

$.validator.unobtrusive.parseDynamicContent = function (selector) {
    var $selector = $(selector),
        $jqValUnob = $.validator.unobtrusive,
        selectorsDataValAttr = $selector.attr('data-val'),
        $validationInputs = $selector.find(':input[data-val=true]');

    if ((selectorsDataValAttr !== 'true') && 
        ($validationInputs.length === 0)) { 
        return; 
    }

    if (selectorsDataValAttr === 'true') {
        $jqValUnob.parseElement(selector, true);
    }

    $validationInputs.each(function () {
        $jqValUnob.parseElement(this, true);
    });

    //get the relevant form
    var $form = $selector.first().closest('form');

    $jqValUnob.syncValdators($form);
};

/* synchronizes the unobtrusive validation with jquery validator */
$.validator.unobtrusive.syncValdators = function ($form) {
    if ($.hasData($form[0])) {
        var unobtrusiveValidation = $form.data('unobtrusiveValidation'),
            validator = $form.validate();

        // add validation rules from unobtrusive to jquery
        $.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
            if (validator.settings.rules[elname] == undefined) {
                var args = {};
                $.extend(args, elrules);
                args.messages = unobtrusiveValidation.options.messages[elname];
                $("[name='" + elname + "']").rules("add", args);
            } else {
                $.each(elrules, function (rulename, data) {
                    if (validator.settings.rules[elname][rulename] == undefined) {
                        var args = {};
                        args[rulename] = data;
                        args.messages = unobtrusiveValidation.options.messages[elname][rulename];
                        $("[name='" + elname + "']").rules("add", args);
                    }
                });
            }
        });
        // remove all validation rules from jquery that arn't in unobtrusive
        $.each(validator.settings.rules, function (elname, elrules) {
            if (unobtrusiveValidation.options.rules[elname] === undefined) {
                delete validator.settings.rules[elname];
            } else {
                $.each(elrules, function (rulename, data) {
                    if (rulename !== "messages" && unobtrusiveValidation.options.rules[elname][rulename] === undefined) {
                        delete validator.settings.rules[elname][rulename];
                    }
                });
            }
        });
    }        
};

$.validator.unobtrusive.unparseContent = function (selector) {
    var $selector = $(selector);

    // if its  a text node, then exit
    if ($selector && $selector.length > 0 && $selector[0].nodeType === 3) {
        return;
    }

    var $form = $selector.first().closest('form'), 
        unobtrusiveValidation = $form.data('unobtrusiveValidation');

    $selector.find(":input[data-val=true]").each(function () {
        removeValidation($(this), unobtrusiveValidation);
    });
    if ($selector.attr('data-val') === 'true') {
        removeValidation($selector, unobtrusiveValidation);
    }
    $.validator.unobtrusive.syncValdators($form);
};

function removeValidation($element, unobtrusiveValidation) {
    var elname = $element.attr('name');
    if (elname !== undefined) {
        $element.rules('remove');
        if (unobtrusiveValidation) {
            if (unobtrusiveValidation.options.rules[elname]) {
                delete unobtrusiveValidation.options.rules[elname];
            }
            if (unobtrusiveValidation.options.messages[elname]) {
                delete unobtrusiveValidation.options.messages[elname];
            }
        }
    }
}

Donc, fondamentalement, cela fonctionne toujours de la même manière que la solution de Xhalent ci-dessus, mais j'ai ajouté la possibilité de supprimer les règles pour les éléments que vous supprimez du dom. Ainsi, lorsque vous supprimez des éléments du Dom et que vous souhaitez que ces règles de validation soient également supprimées, appelez:

$.validator.unobtrusive.unparseContent('input.something');
Evan Larsen
la source
1

J'ai trouvé le script de code de @ Xhalent dans mon code et j'allais le supprimer parce que je ne l'utilisais pas, ce qui m'a conduit à cette question SO.

Ce code est assez propre et simple:

jQuery.fn.unobtrusiveValidationForceBind = function () {
    //If you try to parse a form that is already parsed it won't update
    var $form = this
       .removeData("validator") /* added by the raw jquery.validate plugin */
            .removeData("unobtrusiveValidation");  /* added by the jquery     unobtrusive plugin */

    $form.bindUnobtrusiveValidation();
}

Ensuite, pour appeler cette extension jQuery, utilisez simplement un sélecteur pour saisir votre formulaire:

$('#formStart').unobtrusiveValidationForceBind();

Alto!

Brian Ogden
la source
1

J'ai essayé la réponse de viggity et au début, tout a semblé fonctionner. Mais au bout d'un moment, j'ai remarqué que la validation devenait douloureusement lente avec les éléments plus dynamiques que j'avais ajoutés. La raison en est que sa solution ne dissocie pas les gestionnaires d'événements, mais en ajoute de nouveaux à chaque fois. Donc, si vous ajoutez 5 éléments, la validation est exécutée 6 fois au lieu d'une seule. Pour résoudre ce problème, vous devez dissocier les événements en plus des appels removeData.

$("form").removeData("validator")
         .removeData("unobtrusiveValidation")
         .off("submit.validate click.validate focusin.validate focusout.validate keyup.validate invalid-form.validate");
$.validator.unobtrusive.parse("form");
Benedikt Langer
la source
1

En cas de contenu dynamique, vous devez mettre à jour les validations discrètes comme ci-dessous et vérifier si Formest valide lors de la soumission.

function UpdateUnobtrusiveValidations(idForm) {
    $(idForm).removeData("validator").removeData("unobtrusiveValidation");
    $.validator.unobtrusive.parse($(idForm));
};


$('#idDivPage').on('click', '#idSave', function (e) {
    e.preventDefault();
    if (!$('#idForm').valid()) {
        // Form is invalid … so return
        return false;
    }
    else {
        // post data to server using ajax call
        // update Unobtrusive Validations again
        UpdateUnobtrusiveValidations('#idForm');
    }
});
Jagdeesh Motegowda
la source
0

Cela fait un moment que je tripote cela, abandonne des solutions et réessaye plus tard (quand j'avais du temps libre, croyez-le ou non).

Je ne sais pas si ce comportement aurait changé dans les versions plus récentes de jquery (nous utilisons la 1.7.2) depuis que ce fil a été créé ou commenté en dernier, mais j'ai trouvé que cela .parseElement(inputElement)fonctionne bien lorsque j'essaie d'ajouter des éléments créés dynamiquement à un formulaire qui a déjà un validateur chargé. Cela a déjà été suggéré par @jamesfm (15 février 11) dans l'un des commentaires ci-dessus, mais je l'ai négligé les premières fois où je travaillais là-dessus. Je l'ajoute donc en tant que réponse distincte pour la rendre plus évidente et parce que je pense que c'est une bonne solution et ne nécessite pas autant de frais généraux. Ce n'est peut-être pas pertinent pour toutes les questions soulevées dans les réponses ultérieures, mais je pense que ce serait une solution à la question initiale. Voici comment j'ai fait fonctionner le mien:

//row & textarea created dynamically by an async ajax call further up in the code
var row = ...; //row reference from somewhere
var textarea = row.find("textarea");
textarea.val("[someValue]");

//add max length rule to the text area
textarea.rules('add', {
    maxlength: 2000
});
//parse the element to enable the validation on the dynamically added element
$.validator.unobtrusive.parseElement(textarea);
Ben
la source
0

Tout d'abord, je pense que l'appel devrait être à .validator, pas valider, alors vous devez passer l'identifiant du formulaire

$.validator.unobtrusive.parse("#id");
Chris Allmark
la source
Je suppose que vous avez chargé les scripts jquery.validate et jquery.validate.unobtrusive et appelé les méthodes Html.EnableClientValidation () et Html.EnableUnobtrusiveJavaScript ()? Pouvez-vous publier un exemple de code pour votre page de base et le formulaire chargé dynamiquement peut-être?
Chris Allmark
0

Si vous avez besoin d'ajouter et de supprimer des éléments avec la possibilité que certaines erreurs soient déjà affichées, c'est ce que j'ai fourni. Il est basé principalement sur différentes idées sur cette page de questions. J'utilise le intégré au destroy()lieu de simplement supprimer l'attribut data pour JQuery validate.

function resetValidator($form: JQuery) {
    $form.validate().destroy();

    //reset unobtrusive validation summary, if it exists
    $form.find("[data-valmsg-summary=true]")
        .removeClass("validation-summary-errors")
        .addClass("validation-summary-valid")
        .find("ul").empty();

    //reset unobtrusive field level, if it exists
    $form.find("[data-valmsg-replace]")
        .removeClass("field-validation-error")
        .addClass("field-validation-valid")
        .empty();

    $form.removeData("unobtrusiveValidation");
}

Vous l'appelez avant de modifier dynamiquement les entrées du formulaire. Vous réinitialisez ensuite la validation après.

resetValidator($form);
//add or remove inputs here ...
$.validator.unobtrusive.parse($form);

Remarque: Si certaines ou toutes les entrées ont été validées et comportent des erreurs, ces erreurs seront réinitialisées ... mais elles reviendront correctement lors de la prochaine validation.

Yepeekai
la source