1

I'm working on an MVC4 app and needed some specific validation on a particular form. So I followed (several) tutorials on how to do this. Starting with a custom attribute:

public class CheckDuplicateElementNameAttribute : 
    ValidationAttribute, IClientValidatable
{
  // Server side check omitted
  public IEnumerable<ModelClientValidationRule>
        GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
  {
        ModelClientValidationRule rule = new ModelClientValidationRule();
        rule.ErrorMessage = this.ErrorMessage;
        rule.ValidationType = "elementname";
        yield return rule;
  }
}

So then I add the attribute to the model's property like so:

public class HygieneElementModel
{

    [CheckDuplicateElementName
        (ErrorMessage="There is already an element with that name")]
    public string ShortName { get; set; }

}

And finally added the js method to the page:

$(document).ready(function () {
        jQuery.validator.addMethod('elementname', function (val, element) {
        console.log('validating');
        return false;
    }, '');

    jQuery.validator.unobtrusive.adapters.add('elementname', {}, function (options) {
        options.rules['elementname'] = true;
        options.messages['elementname'] = options.message;
    });

    jQuery.validator.unobtrusive.parse();
}

And the validation method completely fails to run. When I move the lines out of the document.ready function and just have them run as soon as they are loaded, it works fine. Now, a lot of the examples I've followed - many of them from SO, show the addMethod calls being made from within document.ready, so why does mine not work this way?

Questions:

  1. Why is this?
  2. When are the default adapters registered and how do they parse the html before it is loades?
  3. Is there a risk that on a slow connection the validation adapter still won't be registered on time?

Version Detials

jQuery 1.11.0

jQuery.validation 1.8.1

Mircosoft.jQuery.Unobstrusive.Ajax 3.2.0

Mircosoft.jQuery.Unobstrusive.Validation 3.2.0

CurlyPaul
  • 1,138
  • 1
  • 10
  • 29

1 Answers1

4

This article from Brad Wilson covers all your questions.

1 Why is this?

See Parsing New HTML For Validation of the article. It says

The unobtrusive client validation script automatically parses the initial set of HTML for validation rules when the page has finished loading. If your page dynamically adds new HTML content (perhaps throught Ajax or through client-side application code), you may wish to parse that new HTML for client validation on the new HTML elements.

To parse new HTML, you can call the jQuery.validator.unobtrusive.parse() method, passing it a selector for the HTML that you would like to be parsed.

I believe that jquery.validate.unobtrusive.js is included in the page before your document ready function and as it uses it's own document ready function which parses html page - it doesn't use your adapter, because your document ready handler has not been executed at that moment (no custom adapters available). When you move adding your adapter outside document ready function, they're available at the jquery.validate.unobtrusive.js's document ready.

2 When are the default adapters registered and how do they parse the html before it is loades?

See Bridging HTML and jQuery Validate: Adapters section of the article:

There is an adapter collection available at jQuery.validator.unobtrusive.adapters.

You can see jquery.validate.unobtrusive.js source code to ensure that all initialization (default adapters as well) is happen right in the script, which, again, executes before your page's document ready.

The document parsing is happen in the end of the script - in it's document ready function:

$(function () {
    $jQval.unobtrusive.parse(document);
});

3 Is there a risk that on a slow connection the validation adapter still won't be registered on time?

Well - there's no magic at all, if you understand the script behaviour correctly and if you do initialization in the right way, it'll all be ok :)

To ensure your adapters are using, you can:

1) register them outside document ready as you did when it all worked.

2) register them in document ready function, but move <script> tag which includes jquery.validate.unobtrusive.js below your document ready function.

3) call

jQuery.validator.unobtrusive.parse(document);

manually after registering your custom adapters (if you're not so much concern about performance).

Ivan Samygin
  • 4,210
  • 1
  • 20
  • 33