Skip to content

Instantly share code, notes, and snippets.

@akatakritos
Last active June 19, 2018 19:19
Show Gist options
  • Save akatakritos/1ddf74f24a3e5d499151cd85f41a96c0 to your computer and use it in GitHub Desktop.
Save akatakritos/1ddf74f24a3e5d499151cd85f41a96c0 to your computer and use it in GitHub Desktop.
RequiredIf Validator
// [RequiredIf("SomeOtherProperty")] -- required if the other property is true
// [RequiredIf("SomeIntProperty", OtherPropertyValue = 42)] -- required if the other property is 42
public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
public string OtherPropertyName { get; }
public object OtherPropertyValue { get; set; }
public RequiredIfAttribute(string otherPropertyName)
{
OtherPropertyName = otherPropertyName;
}
public override bool RequiresValidationContext => true;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var prop = validationContext.ObjectType.GetProperty(OtherPropertyName);
if (prop == null)
throw new InvalidOperationException($"Could not find property {OtherPropertyName} on type {validationContext.ObjectType}.");
var otherValue = prop.GetValue(validationContext.ObjectInstance);
bool isRequired;
if (otherValue is true)
isRequired = true;
else
{
isRequired = otherValue?.Equals(OtherPropertyValue) ?? false;
}
if (isRequired)
{
if (value == null || (value is string s && s.Trim() == ""))
{
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
return ValidationResult.Success;
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, name, OtherPropertyName);
}
// adds a data-val-requiredif attribute data-val-requireif-other="OtherPropertyName" data-val-requiredif-value="42"
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule()
{
ErrorMessage = FormatErrorMessage(metadata.DisplayName),
ValidationType = "requiredif",
ValidationParameters =
{
{
"other", OtherPropertyName
}
}
};
if (OtherPropertyValue != null)
{
rule.ValidationParameters["value"] = OtherPropertyValue.ToString();
}
yield return rule;
}
}
$.validator.addMethod('requiredif', (value, element) => {
const otherFieldValue = element.getAttribute('data-val-requiredif-value'); // optional
const otherFieldName = element.getAttribute('data-val-requiredif-other');
const otherFieldElement = element.form[otherFieldName];
if (otherFieldValue) {
if (otherFieldElement.value === otherFieldValue) {
// the other field matches the value, so this field is required, and
// thus valid only if a value is given
return Boolean(value);
}
// the other field does not match the value, so this element is not
// required, and thus always valid
return true;
} else {
// compare if its a checked checkbox or an input with something in it
if ((otherFieldElement.type === 'checkbox' && otherFieldElement.checked)
|| (otherFieldElement.type !== 'checkbox' && otherFieldElement.value)) {
// the other field is checked or provided, so this field is required, and
// thus valid only if it has a value
return Boolean(value);
}
// the other field does not match the value, so this element is not
// required, and thus always valid
return true;
}
});
public class SomeModel
{
public bool SendMeMail { get; set; }
[RequiredIf("SendMeMail")]
public string EmailAddress { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment