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

StackOverflow https://stackoverflow.com/questions/10236198

Question

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.

Was it helpful?

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

OTHER TIPS

Cannot do it exactly right now, but the problem is in the client javascript function:

jQuery.validator.addMethod("requiredif" ...

The js is not sophisticated enough to cope with complex view models where there may be a model prefix. If you take a look at Microsoft's jquery.validate.unobstrusive.js (in the Scripts folder over every MVC3 application), you will find some useful methods including getModelPrefix and appendModelPrefix. You can take a similar approach and change the requiredIf validation method - take a look at the equalto method in jquery.validate.unobstrusive.js for a helping hand.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top