I was looking for some advice on the best way to go about implementing a validation attribute that does the following.
Model
public class MyInputMode
The main difference from other solutions here is that this one reuses logic in RequiredAttribute
on the server side, and uses required
's validation method depends
property on the client side:
public class RequiredIf : RequiredAttribute, IClientValidatable
{
public string OtherProperty { get; private set; }
public object OtherPropertyValue { get; private set; }
public RequiredIf(string otherProperty, object otherPropertyValue)
{
OtherProperty = otherProperty;
OtherPropertyValue = otherPropertyValue;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
PropertyInfo otherPropertyInfo = validationContext.ObjectType.GetProperty(OtherProperty);
if (otherPropertyInfo == null)
{
return new ValidationResult($"Unknown property {OtherProperty}");
}
object otherValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);
if (Equals(OtherPropertyValue, otherValue)) // if other property has the configured value
return base.IsValid(value, validationContext);
return null;
}
public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule();
rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
rule.ValidationType = "requiredif"; // data-val-requiredif
rule.ValidationParameters.Add("other", OtherProperty); // data-val-requiredif-other
rule.ValidationParameters.Add("otherval", OtherPropertyValue); // data-val-requiredif-otherval
yield return rule;
}
}
$.validator.unobtrusive.adapters.add("requiredif", ["other", "otherval"], function (options) {
var value = {
depends: function () {
var element = $(options.form).find(":input[name='" + options.params.other + "']")[0];
return element && $(element).val() == options.params.otherval;
}
}
options.rules["required"] = value;
options.messages["required"] = options.message;
});