Validate 1 field (unobtrusive) when other field changes, and check only 1 rule

asp.net-mvc-4, jquery, unobtrusive-validation

Solution

This might work for you...

$('form').data('validator').element('#Key')

This grabs the validator off of your form, and forces validation on an individual item.

http://docs.jquery.com/Plugins/Validation/Validator/element#element

UPDATE

See if this continues to help!

$.extend($.validator.prototype, {
        elementWithRule: function(element, rule) {
            element = this.clean(element);
            this.lastElement = element;
            this.prepareElement(element);
            this.currentElements = $(element);
            var result = this.checkSpecificRule(element, rule);
            if (result) {
                delete this.invalid[element.name];
            } else {
                this.invalid[element.name] = true;
            }
            if (!this.numberOfInvalids()) {
                // Hide error containers on last error
                this.toHide = this.toHide.add(this.containers);
            }
            this.showErrors();
            return result;
        },
        checkSpecificRule: function(element, rule) {
            element = this.clean(element);

            // if radio/checkbox, validate first element in group instead
            if (this.checkable(element)) {
                element = this.findByName(element.name).not(this.settings.ignore)[0];
            }

            var findRule = { },
                checkRule = $(element).rules()[ rule ];
            var rules;

            if (checkRule) {
                findRule[rule] = checkRule;
                rules = findRule;
            }

            if (!rules) {
                return;                
            }
            var dependencyMismatch = false;
            for (var method in rules) {
                var rule = { method: method, parameters: rules[method] };
                try {
                    var result = $.validator.methods[method].call(this, element.value.replace( /\r/g , ""), element, rule.parameters);

                    // if a method indicates that the field is optional and therefore valid,
                    // don't mark it as valid when there are no other rules
                    if (result == "dependency-mismatch") {
                        dependencyMismatch = true;
                        continue;
                    }
                    dependencyMismatch = false;

                    if (result == "pending") {
                        this.toHide = this.toHide.not(this.errorsFor(element));
                        return;
                    }

                    if (!result) {
                        this.formatAndAdd(element, rule);
                        return false;
                    }
                } catch(e) {
                    this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
                        + ", check the '" + rule.method + "' method", e);
                    throw e;
                }
            }
            if (dependencyMismatch)
                return;
            if (this.objectLength(rules))
                this.successList.push(element);
            return true;
        }
    });

// Then use it like this...
$('form').data('validator').elementWithRule('#Key', 'required');

There didn't appear to be any built in way to do this, so I just hacked something together! :)

Problem

Is there any way to trigger a specific jquery-unobtrusive rule on one field, when the value in another field changes? I have a form with two date fields (say start/end) on it, with validation that `end` must be greater than `start`. This works fine in the simple case of changing `end` after `start` is already set. What it doesn't do is allow for is: - setting `end` first and then setting `start` - changing `start` after both have already been set, and violating the constraint Server side validation will catch it of course, but it looks bad to have the error on `end` stay set even after you have fixed `start`, or no error showing up when the value in `end` is changed to an invalid value. The reason to trigger a specific rule is that I don't want to fire off the `required` or `date` format rules on the same field before the user has had a chance to enter a value. The form starts off 'clean'. However, if that isn't possible then firing all the rules is ok. Sorry for no code samples, but I don't even know where to start with this. Update: What i've done for the moment is to dig around in the model (since this is an asp.net mvc project), find the attribute, and read it's properties directly. ``` var controllerCtx = ViewContext.Controller.ControllerContext; var da = ViewData.ModelMetadata.GetValidators(controllerCtx) .SelectMany(x => x.GetClientValidationRules()) .Where(x => x.ValidationType == "isdateafter") .FirstOrDefault(); var otherid = da == null ? "" : da.ValidationParameters["propertytested"]; ``` Then in the normal HTML part, I do a test on the `start` and see if it is a date picker, then wire up a basic check, and fire off all validation rules. Since there aren't many rules, I just check to see if there is a value in the `end` field before running them. I'd like to use the ingenious solution below, and will give it a go when I have a bit of free time this week. ``` @if (otherid != "") { <text> var other = $("#@otherid"); if (other && other.hasClass('hasDatepicker')) { // if the other box is a date/time picker other.datetimepicker('option', 'onSelect', function(dateText, instance) { var lowerTime = $(this).datetimepicker('getDate'); $("#@id").datetimepicker('option', 'minDate', new Date(lowerTime.getTime())); if ($("#@id").val()) { // if there is a value in the other $('form').data('validator').element('#@id'); } }); } </text> } ```

Original source