0

I have the following class used for custom validation:

[AttributeUsage(AttributeTargets.Property, AllowMultiple=false, Inherited=true)]
public sealed class RequiredIfAnyTrueAttribute : ValidationAttribute, IClientValidatable
{
    private const string DefaultErrorMessage = "{0} is required";

    public List<string> OtherProperties { get; private set; }

    public RequiredIfAnyTrueAttribute(string otherProperties)
        : base(DefaultErrorMessage)
    {
        if (string.IsNullOrEmpty(otherProperties))
            throw new ArgumentNullException("otherProperty");

        OtherProperties = new List<string>(otherProperties.Split(new char[] { '|', ',' }));
    }

    public override string FormatErrorMessage(string name)
    {
        return string.Format(ErrorMessageString, name);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null)
        {
            foreach (string s in OtherProperties)
            {
                var otherProperty = validationContext.ObjectType.GetProperty(s);
                var otherPropertyValue = otherProperty.GetValue(validationContext.ObjectInstance, null);

                if (otherPropertyValue.Equals(true))
                    return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
            }
        }

        return ValidationResult.Success;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var clientValidationRule = new ModelClientValidationRule()
        {
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "requiredifanytrue"
        };

        clientValidationRule.ValidationParameters.Add("otherproperties", string.Join("|",OtherProperties));

        return new[] { clientValidationRule };
    }
}

My ViewModel is:

public class SampleViewModel
{
    public bool PropABC { get; set; }
    public bool PropXYZ { get; set; }

    [RequiredIfAnyTrue("PropABC|PropXYZ")]
    public int? TestField { get; set; }
}

When my strongly typed view renders, everything sees to work fine. If PropABC or PropXYZ is selected then I am required to enter a value for TestField. Both client and server-side validation is functional.

However, given the following sequence of events:

  1. check PropABC
  2. submit form
  3. client-side validation fires for TestField required
  4. uncheck PropABC
  5. client validation does not re-fire and validation message remains until form submit

In order to resolve #5 I would typically attach click events to the checkboxes via jquery onready to refire the validation.

Is there a preferred/recommended way to manually force client-side validation given MVC3 + unobstrusive + jquery?

1
  • Could you post the custom client side validator as well? Commented Aug 25, 2011 at 21:47

3 Answers 3

1

Shawn, attaching to events is the best approach to get validation to refire.

I would suggest creating a class called "validate" (or something along those lines), adding it to each element to be validated, and then use jQuery to attach to the click and blur events (and possibly the change event) of each element with that class, and validate the element like so:

$("form").validate().element(this);
Sign up to request clarification or add additional context in comments.

Comments

1

Do you need to write your own attributes? If not I think you may be able to avoid "reinventing the wheel"

FoolProof works great. you get get it as a NuGet package.

NuGet: install-package foolproof

It includes a lot of greate attributes for various combinations of on-the-fly required fields and such.

4 Comments

I tried FoolProof but could not get it to work with my scenario. I need a given field to be required if any of several other fields are true. FoolProof does not provide that built-in and I couldn't figure out how to extend it successfully. My Post to Foolproof Discussion
IMO: I would fight hard to [learn how to] get Foolproof to work even if that would require extending it. The time you will spend upfront will be nowhere near the time you will spend to write your own solution from scratch.
If I ignore my requirement to validate multiple targets and use FoolProof's RequireIfTrue attribute out-of-the-box against a single target property the same problem I describe above exists. Validation does not fire when the checkbox is unselected, instead it only fires when submit is clicked again. Does there exist a better technique for re-validating upon checkbox interaction than attaching onclick events via jquery onready?
@Shawn - I haven't used Foolproof, but what happens if you use multiple RequiredIfTrue attributes on a single property?
0

FoolProof is still in beta and does not work with nested viewmodel, also with arrays

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.