0

I'm trying to get a custom rule "mustbetrue" working. Based loosely on this question: My issue is that when I submit the form the client side validation doesn't give me an error (doesn't make the validation text appear). In addition I've put a break point in the jscript validation method and it never gets fired. The wireup code that adds the adapter does get fired. No errors in the console.

What am I doing wrong?

This is what I have server-side:

public class MustBeTrueAttribute : ValidationAttribute, IClientValidatable
{
    public override bool IsValid(object value)
    {
        if (value == null) return false;
        try
        {
            return Convert.ToBoolean(value);
        }
        catch (InvalidCastException)
        {
            return false;
        }
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata,
                                                                           ControllerContext context)
    {
        yield return new ModelClientValidationRule
            {
                ErrorMessage = this.ErrorMessage,
                ValidationType = "mustbetrue"
            };
    }
}

and

public class MustBeTrueAttributeAdapter : DataAnnotationsModelValidator<MustBeTrueAttribute>
{
    public MustBeTrueAttributeAdapter(ModelMetadata metadata, ControllerContext context, MustBeTrueAttribute attribute)
        : base(metadata, context, attribute)
    {
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        return new[] { new ModelClientValidationMustBeTrueRule(ErrorMessage) };
    }
}

public class ModelClientValidationMustBeTrueRule : ModelClientValidationRule
{
    public ModelClientValidationMustBeTrueRule(string errorMessage)
    {
        ErrorMessage = errorMessage;
        ValidationType = "mustbetrue";
    }
}

and in the global.asax

    protected void Application_Start()
    {
        // stuff
        DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MustBeTrueAttribute), typeof(MustBeTrueAttributeAdapter));
        // stuff
    }

and on the object:

[MustBeTrue(ErrorMessageResourceName = "Register_TermsNotAccepted", ErrorMessageResourceType = typeof(Resources.Global))]
public bool AcceptedTerms { get; set; }

client side:

$(document).ready(function () {
    jQuery.validator.addMethod("mustbetrue", function (value, element) {
        if (!this.depend(param, element))
            return "dependency-mismatch";
        return element.checked;
    });
    jQuery.validator.unobtrusive.adapters.addBool("mustbetrue", "mustbetrue");
});

and the relevant HTML that is output:

<input data-val="true" data-val-mustbetrue="You must accept the terms and conditions" data-val-required="The AcceptedTerms field is required." id="AcceptedTerms" name="AcceptedTerms" type="checkbox" value="true" class="valid">
Community
  • 1
  • 1
Quibblesome
  • 25,225
  • 10
  • 61
  • 100
  • Not to stray from the overall goal, but isn't `Required` enough on a checkbox? Unchecked checkboxes aren't sent across the wire, are they (therefore enforcing `Required`)? – Brad Christie Sep 06 '13 at 16:50
  • Yes I've heard people state that it works without having to add a new rule. However in practice I've never got it working. Even with the added combination of min max either at 1 or 4. – Quibblesome Sep 06 '13 at 16:56
  • @Brad Since a non-null boolean would always have a value, either False or True, then it will always satisfy the Required attribute. What is needed here is not a Required attribute, but validation that ensures it matches a certain value. Required just checks whether or not a value is present, but doesn't care whether that value is 0, 1, true, false, etc. – AaronLS Sep 06 '13 at 17:55

1 Answers1

1

If you've already checked that client validation is enabled (either in configuration or in code) then I guess it is because you're adding your adapter after unobtrusive validation scripts parses html see my answer here for details and possible options

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