8

I have a list of Pair of radio buttons (Yes/No):

Q1.(Y)(N) 
Q2.(Y)(N) 
Q3.(Y)(N) 
Q4.(Y)(N)

and I have one property in my model public string MedicalExplanation { get; set; }

My goal is to make Explanation required if any of the radio button has been set to true.

My first try was to use [Required] but it does not handle conditions.

Then I decided to use third party tool like MVC Foolproof Validation I used it like this: [RequiredIf("Q1", true, ErrorMessage = "You must explain any \"Yes\" answers!")]

Now the problem is I don't know how to make it required if any of the other Q2, Q3, Q4 is checked.

Please advice

meda
  • 45,103
  • 14
  • 92
  • 122

2 Answers2

17

In your ViewModel, create a bool property like this:

public bool IsMedicalExplanationRequired
{
   get
   {
       return Q1 || Q2 || Q3 || Q4;
   }
}

Then, use your RequiredIf attribute like this:

[RequiredIf("IsMedicalExplanationRequired", true, ErrorMessage = "You must explain any \"Yes\" answers!")]

UPDATE:

If your Q1 - Q4 properties are of type bool?, just change the IsMedicalExplanationRequired property like below:

public bool IsMedicalExplanationRequired
{
   get
   {
       return Q1.GetValueOrDefault() || Q2.GetValueOrDefault() || Q3.GetValueOrDefault() || Q4.GetValueOrDefault();
   }
}
ataravati
  • 8,891
  • 9
  • 57
  • 89
  • in my application Q1 , Q2 , Q3 , Q4 are booleans (yes or no) so I am getting the error `Operator '||' cannot be applied to operands of type 'bool?' ` – meda Jul 22 '13 at 19:46
  • Great ! You the best ! haha! – meda Jul 22 '13 at 20:21
  • @Jimmy, what do you mean it doesn't work? What happens? – ataravati Jan 05 '15 at 15:48
  • I mean it doesn't work client-side, sorry. My use case is slightly different, I want to enforce both client & server-side that either an email or a phone number must be entered. – Jimmy Jan 05 '15 at 15:56
  • @Jimmy, Yes, this only works on the server-side. You can use Remote validation for the client-side, or use jQuery validation. – ataravati Jan 05 '15 at 19:19
  • This is such a ludicrously simple solution that I feel incredibly stupid for not thinking of it myself! Great work @ataravati – Nick Coad Jun 25 '15 at 05:42
  • @Crock, this code is for the server side. For the client side, whatever logic you have for one checkbox you can use for 4. Check this post: https://stackoverflow.com/questions/6573487/jquery-validation-select-required-if-checkbox-checked – ataravati Oct 27 '17 at 15:35
3

This is how I did it:

First I created a custom validation attribute which gets a string array of fields to check passed in:

public class ValidateAtLeastOneChecked : ValidationAttribute {
    public string[] CheckBoxFields {get; set;}
    public ValidateAtLeastOneChecked(string[] checkBoxFields) {
        CheckBoxFields = checkBoxFields;
    }

    protected override ValidationResult IsValid(Object value, ValidationContext context) {
        Object instance = context.ObjectInstance;
        Type type = instance.GetType();

        foreach(string s in CheckBoxFields) {
            Object propertyValue = type.GetProperty(s).GetValue(instance, null);
            if (bool.Parse(propertyValue.ToString())) {
                return ValidationResult.Success;
            }
        }
        return new ValidationResult(base.ErrorMessageString);
    }
}

Then I use it like this (I am using resource files to localize my error messages):

[ValidateAtLeastOneChecked(new string[] { "Checkbox1", "Checkbox2", "Checkbox3", "Checkbox4" }, ErrorMessageResourceType=typeof(ErrorMessageResources),ErrorMessageResourceName="SelectAtLeastOneTopic")]
public bool Checkbox1{ get; set; }
public bool Checkbox2{ get; set; }
public bool Checkbox3{ get; set; }
public bool Checkbox4{ get; set; }

It is only actually setting the error on the first checkbox. If you are using the built in css highlighting to highlight fields in error you will need to modify this slightly to make it look right, but I felt this was a clean solution which was reusable and allowed me to take advantage of the support for resource files in validation attributes.

Matthew
  • 9,851
  • 4
  • 46
  • 77