Search code examples
jqueryasp.net-mvcunobtrusive-validation

Unobstrusive "ignore" setting not working


This is something of an odd one. There are many questions on SO in regard to setting the ignore property for unobtrusive validation's settings object.

The scenario: I have a table generated by iterating over a model in MVC and I auto-populate a blank row at the bottom by inserting a blank model at the server side (it's part of the requirements, non-negotiable). I don't want to validate this blank row if the user hasn't touched it but do if they have.

To solve this, I generate the table as normal. Using jquery, I auto mark any blank rows with a class of "blank". I can see this happening only for blank rows in the table by viewing the source.

Now, if in the document.read() call on the client I have;

$.validator.unobtrusive.parse('form');
var form = $('form').get(0);
var settings = $.data(form, 'validator').settings;
settings.ignore = ':hidden,.blank';

This works just fine. Hitting submit will not trigger validation on blank rows even when I add new ones. However, validation doesn't happen on any of the populated rows apart from the first row.

To solve this, I created a function reattachValidation() that is called whenever I add a new row so that validation will trigger for the new rows. The code was modified to:

function reattachValidation() {
    var forms = $('form');
    forms.removeData('validator');
    forms.removeData('unobtrusiveValidation');

    $.validator.unobtrusive.parse('form');
    var form = $('form').get(0);
    var settings = $.data(form, 'validator').settings;
    settings.ignore = ':hidden,.blank';
}

Now the code above will validate any new rows dynamically added to the table but will also validate the blank rows which still have a class of "blank" on the relevant elements. So I can either not validate blank rows and no new rows OR I can validate all rows including those with elements tagged with "blank".

How can I ignore the blank rows while also validating the new rows with user data?


Solution

  • I did eventually get this working.

    In javascript;

    $(function() {
        $.validator.unobtrusive.parse("form");
        var form = $("form").get(0);
        var settings = $.data(form, "validator").settings;
        settings.ignore = ":hidden,.blank";
    });
    
    // This function will attach any dynamic entity (e.g., a new row in a grid) to the
    // MVC unobtrusive validator to be validated at the appropriate time.
    // Usage:    $.validator.unobtrusive.parseDynamicContent(newTableRow);
    (function ($) {
        $.validator.unobtrusive.parseDynamicContent = function (selector) {
            //use the normal unobstrusive.parse method
            $.validator.unobtrusive.parse(selector);
    
            //get the relevant form
            var form = $(selector).closest("form");
    
            //get the collections of unobtrusive validators, and jquery validators
            //and compare the two
            var unobtrusiveValidation = form.data("unobtrusiveValidation");
            var validator = form.validate();
    
            $.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
                if (validator.settings.rules[elname] == undefined) {
                    var args = {};
                    $.extend(args, elrules);
                    args.messages = unobtrusiveValidation.options.messages[elname];
                    //edit:use quoted strings for the name selector
                    $("[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];
                            //edit:use quoted strings for the name selector
                            $("[name='" + elname + "']").rules("add", args);
                        }
                    });
                }
            });
        }
    })($);
    

    Then when adding the new dynamic elements, this was done like so (animation is unnecessary but the call to parseDynamicContent() is;

    selectedTableRow.after(newTableRow);
    newTableRow.fadeIn(500, function () {
        // reattach the MVC validation after adding a new row so that we get our client
        // side validation on the data annotations.
        // NOTE: we do this AFTER the fade in animation as by default the validator will
        //       not hook into any hidden elements - which our row is until the animation
        //       completes.
        $.validator.unobtrusive.parseDynamicContent(newTableRow);
    });