jquery.validate.unobtrusive not working with dynam

2018-12-31 19:45发布

问题:

I am working with ASP.Net MVC3, the easier way to use the client validation would be enabling the jquery.validate.unobtrusive. Everything works fine, for stuff that\'s right from server.

But when I try to inject some new \'inputs\' with javascript, and I knew that I need to call $.validator.unobtrusive.parse() to rebind the validations. But still, all those dynamic injected fields are not functioning.

Even worse, I try to manually bind using jquery.validate and it is not working either. Any thoughts?

回答1:

I\'ve created an extension for the jquery.validate.unobtrusive library that solved this problem for my situation - it might be of interest.

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



回答2:

I tried Xhalent\'s approach but unfortunately it wasn\'t working for me. Robin\'s approach did work and didn\'t work. It worked great for dynamically added elements, but if you tried to use JQuery to remove all the validation attributes and spans from the DOM, the validation library still would try to validate them.

However, if you remove the form\'s \"unobtrusiveValidation\" data in addition to \"validationData\", it worked like a charm for dynamically adding and removing elements that you want validated or not validated.

$(\"form\").removeData(\"validator\");
$(\"form\").removeData(\"unobtrusiveValidation\");
$.validator.unobtrusive.parse(\"form\");


回答3:

I actually really like the simplicity of @viggity and @Robins solution, so I turned it into a quick little plugin:

(function ($) {

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

        $.validator.unobtrusive.parse(form);

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

Example usage:

$(\"#DischargeOutcomeNumberOfVisits\")
    .attr(\"data-val-range-min\", this.checked ? \"1\" : \"2\")
    .updateValidation();


回答4:

I\'m having the same problem. I discovered it\'s not possible to call $.validator.unobtrusive.parse() on the same form twice. When loading the form initially from the server the form is parsed automatically by the unobtrusive library. When you add an input element dynamically to the form and call $.validator.unobtrusive.parse() again, it won\'t work. The same goes for parseElement().

The unobtrusive lib calls the validate method of the jquery validate plugin to set all the rules and messages. Problem is, when called again, the plugin doesn\'t update the new set of rules its given.

I found one crude solution: Before calling the parse method on the unobstrusive lib, i throw away the form validator:

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

Now, when the validate method is called by the unobtrusive lib, all rules and messages are recreated including the dynamically added inputs.

Hope this helps



回答5:

I am using MVC 4 and JQuery 1.8, looks like the following piece of code is needed to enable Jquery to validation dynamically injected content via Ajax, or Jquery into the DOM.

I have made a modular function which accepts the Jquery object of the newly added element. If you have cloned a new table with id tblContacts using Jquery on click of a button, then include the function below in your js file

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

and call it like this:

fnValidateDynamicContent(\"#tblContacts\")


回答6:

Taking from Xhalent\'s solution marked as answer above, I expanded on it a bit.

$.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];
            }
        }
    }
}

So basically it still works the same as Xhalent\'s solution above but I added the ability to remove rules for elements you remove from the dom. So, when you remove elements from the Dom and you want those validation rules removed also then call:

$.validator.unobtrusive.unparseContent(\'input.something\');


回答7:

Why not use the rules function directly from jquery validation doc. Like this:

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


回答8:

I found @Xhalent\'s code script in my code and was going to delete it because I was not using it, which lead me to this SO question.

This code is pretty clean and 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();
}

Then, to call this jQuery extension, just use a selector to grab you form:

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

Viola!



回答9:

In case of dynamic contents you need to update Unobtrusive Validations as below and check if Form is valid while submitting.

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\');
    }
});


回答10:

I have been fiddling around with this for a while, scrapping solutions and trying again later (when I had some spare time, believe it or not).

I am not sure if this behaviour would have changed in newer versions of jquery (we\'re using 1.7.2) since this thread was created or commented last, but I found that .parseElement(inputElement) works fine when I try to add dynamically created elements to a form that already has a validator loaded. This was already suggested by @jamesfm (Feb 15 \'11) in one of the comments above, but I overlooked it the first few times I was working on this. So I\'m adding it as a separate answer to make it more obvious and because I think it is a good solution and doesn\'t require so much overhead. It might not be relevant for all the issues raised in subsequent answers but I think it would be a solution to the original question. Here\'s how I got mine working:

//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);


回答11:

Firstly, I think the call should be to .validator, not validate then you need to pass in the id of the form

$.validator.unobtrusive.parse(\"#id\");


回答12:

I tried viggity\'s answer and at first everything seemed to work. But after a while i noticed that the validation becomes painfully slow the more dynamically items I added. The reason was that his solution doesn\'t unbind the event handlers, but add new ones each time. So if you add 5 items the validation is executed 6 times instead of only once. To fix this you have to unbind the events additionally to the removeData calls.

$(\"form\").removeData(\"validator\")
         .removeData(\"unobtrusiveValidation\")
         .off(\"submit.validate click.validate focusin.validate focusout.validate keyup.validate invalid-form.validate\");
$.validator.unobtrusive.parse(\"form\");