Question

I'm building a page that renders a series of questions to the page, some of these questions have multiple options other might just require the user to fill in someting in a text box.

Because of the nature of these questions and the way they need to be validated (the whole question needs to be looked at) I came to the conclusion that the out of the box required field validator wouldn't quite cut it.

So I started writing my own and hit a bit of a hurdle ...

In my validation method I pass in 2 possible "error messages" that might occur based on conditions in the validator.

How do I get them in the right place in this context? On the basis that I don't know what the actual error message should be until i get to the failing condition in the validation handler function i need to be able to say to jquery "set this as the error message and fail this field".

$.validator.unobtrusive.adapters.add("myrule", ['enable', 'err1', 'err2'], function (options) {
    var value = {
        enable: options.params.enable,
        err1: options.params.err1,
        err2: options.params.err2
    };
    options.rules["myrule"] = value;
    if (options.message) {
        options.messages["myrule"] = options.message;
    }
});

$.validator.addMethod("myrule", function (value, element, params) {
    var question = $(element).closest('fieldset[data-questionId]');
    var result = validateMyrule(question, params['enable'], params['err1'], params['err2']);
    return result;
});

function validateMyrule(question, enabled, err1, err2) 
{
     // actual code omitted to simplify question

     if(someCondition)
     {
         if(someCondition)
         {
             errorMessage = err1;
         }
         else
         {
             errorMessage = err2;
         }

         return false;
     }

     return true; 
}
Was it helpful?

Solution

Although I did not find a direct method of formatting a message using validator output (such as returning a custom value from the validator and receiving it as a parameter in the message formatter), I was able to use the element data storage in order to get the required effect.

I created a validator:

var ruleValidator = function(val, el){
    var valid = true, error;
    if(val == "a") {
        valid = false;
        error = 0;
    } else if (val == "b") {
        //...
    }
    if(!valid) {
        //store data within element
        $(el).data("errorId", error);
    }
    return valid;
};

which stores the error index in the element, and the error parser:

var parseError = function(val, el){
    var errors = ["err a", "err b"];
    var i = $(el).data("errorId");
    return errors[i];
};

which returns the custom error message.

I then registered them:

$.validator.addMethod("customRule", ruleValidator, parseError);

And it did the trick. Here is a quick demo.

This could be against intended design, but if you know what you are doing and have a good reason for doing this, it appears to be possible.

OTHER TIPS

Seemingly this can't be done by design this is too late in the binding process.

For future reference solved this by using the power of the server and avoiding the situation altogether.

Depending on your rule you have 2 options:

  1. Split your function in to 2 different functions that evaluate and result in the normal way of returning only 1 message.
  2. (how I solved my problem) Determine a "context specific message" on the server and send that through in the adapter code that defines the rule.

The code above then becomes pretty much identical to an out of the box example from the jquery website in my case.

Interesting find that does do the job in some scenarios ...

Using the code in the question and modifying the rule to look something like this ...

function validateMyrule(question, enabled, err1, err2) 
{
     // actual code omitted to simplify question

     if(someCondition)
     {
         if(someCondition)
         {
             $.validator.messages.myRule = err1;
         }
         else
         {
             $.validator.messages.myRule = err2;
         }

         return false;
     }

     return true; 
}

... i was able to get this working, but more complex pages often resulted in some peculiar behaviour that I haven't gotten to the bottom of yet.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top