I am using the example at The Complete Guide To Validation In ASP.NET MVC 3 to create a RequiredIf validation attribute (it's about 1/3 down the page under the heading of "A more complex custom validator"). It all works fine with the exception of one scenario, and that is if I have the need to validate against a complex type. For example, I have the following model:
public class MemberDetailModel
{
public int MemberId { get; set; }
// Other model properties here
public MemberAddressModel HomeAddress { get; set; }
public MemberAddressModel WorkAddress { get; set; }
}
public class MemberAddressModel
{
public bool DontUse { get; set; }
// Other model properties here
[RequiredIf("DontUse", Comparison.IsEqualTo, false)]
public string StreetAddress1 { get; set; }
}
The problem is that when the attribute validation for the StreetAddress property is rendered, it get's decorated with the attribute of data-val-requiredif-other="DontUse"
. Unfortunately, since the address is a sub-type of the main model, it needs to be decorated with a name of HomeAddress_DontUse and not just DontUse.
Strangely enough, the validation works fine for server-side validation, but client-side unobtrusive validation fails with an JS error because JS can't find the object with a name of just "DontUse".
Therefore, I need to find a way to change the ModelClientValidationRequiredIfRule method to know that the property it is validating is a sub-type of a parent type, and if so, prepend the ParentType_
to the "otherProperty" field (e.g. otherProperty becomes HomeAddress_DontUse
.
I have tried passing in typeof(MemberAddressModel)
as a parameter of the attribute, but even when debugging the attribute creation, I can't seem to find any reference to the parent type of HomeAddress or WorkAddress from that type.
Based on the suggestion from The Flower Guy, I was able to come up with the following which seems to work. I simply modified the following in the customValidation.js file:
jQuery.validator.addMethod("requiredif", function (value, element, params) {
if ($(element).val() != '') return true;
var prefix = getModelPrefix(element.name); // NEW LINE
var $other = $('#' + prefix + params.other); // MODIFIED LINE
var otherVal = ($other.attr('type').toUpperCase() == "CHECKBOX") ? ($other.attr("checked") ? "true" : "false") : $other.val();
return params.comp == 'isequalto' ? (otherVal != params.value) : (otherVal == params.value);
});
I also added the following method to that file (within the JQuery block so as to be only privately accessible):
function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1).replace(".","_");
}