Search code examples
asp.net-mvc-3complextypevalidationattribute

Get full name of Complex Type from ModelClientValidationRequiredIfRule method in custom ValidationAttribute


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.


Solution

  • 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(".","_");
    }