MVC2: validation (data annotations) with two field dependencies

Example: We have a conditional field. This conditional field is a radio button with the following two values ​​of yes and no. Let's say the name of this drum is "AAA".

This conditional field "AAA" should only be displayed if the other field of the "BBB" switch is set to yes. (The values ​​for the β€œBBB” switch are also β€œyes” and β€œno.”)

But the conditional field "AAA" should be displayed with the value set to "NO", means "yes", or "no" should be set when the field is first displayed.

The problem arises from the requirement that the conditional field β€œAAA” should ONLY be required when the (non-conditional) field β€œBBB” is set to β€œyes” - and is not required when the field β€œBBB” is set to β€œno”.

(Sounds like I didn't hear anything about the statement if, or? But hold on and keep reading ...)

Believe me, it will not be a problem for me to solve this topic when we use "ModelState", but we are talking here about Validation (Data Annotations), which looks like this:

public class Input1FormModel { [Required(ErrorMessageResourceName="Error_Field_AAA_Empty", ErrorMessageResourceType=typeof(Resources.MyDialog))] public int AAA { get; set; } } 

I fully understand ALSO these lines of code - I believe; -)

...

 //property limits public int UpperBound { get { return DateTime.Now.Year; } } public int LowerBound { get { return 1900; } } 

...

 [NotNullValidator] [PropertyComparisonValidator("LowerBound", ComparisonOperator.GreaterThan)] [PropertyComparisonValidator("UpperBound", ComparisonOperator.LessThanEqual)] public int? XYZ { get; set; } 

But how to solve the dependence described above (AAA ↔ BBB)?

Change "return DateTime.Now.Year;" to a function call that first checks another field and returns true or false? But how to get there the value of another field?

+4
source share
2 answers

You may need to use IDataErrorInfo.

See this question where I answered this:

Refuse IDataErrorInfo and this question I asked about IDataErrorInfo vs. DataAnnotations .

+1
source

You can do this using data annotations, but the annotation should work at the class level, not at the property level, since validationattributes are for individual properties.

Here is an example that I created because the zip code is optional and state is not required if people claim to be in New Zealand, but this is a prerequisite in Australia. This is a complex validation, taking into account the whole model as an input value and using reflection to compare the values ​​of property names passed from the data annotation.

  [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] public class NZPostcodeAttribute : ValidationAttribute { public const string _defaultErrorMessage = "Postcode and State are required for Australian residents"; private readonly object _typeId = new object(); public NZPostcodeAttribute(string countryProperty, string postcodeProperty, string stateProperty) { CountryProperty = countryProperty; PostcodeProperty = postcodeProperty; StateProperty = stateProperty; } public string CountryProperty { get; private set; } public string StateProperty { get; private set; } public string PostcodeProperty { get; private set; } public override object TypeId { get { return _typeId; } } public override string FormatErrorMessage(string name) { return _defaultErrorMessage; } public override bool IsValid(object value) { PropertyDescriptorCollection props = TypeDescriptor.GetProperties(value); object countryValue = props.Find(CountryProperty, true).GetValue(value); object postcodeValue = props.Find(PostcodeProperty, true).GetValue(value); object stateValue = props.Find(StateProperty, true).GetValue(value); string countryString = countryValue == null ? "" : countryValue.ToString(); string postcodeString = postcodeValue == null ? "" : postcodeValue.ToString(); string stateString = stateValue == null ? "" : stateValue.ToString(); bool isValid = true; if (countryString.ToString().ToLower() == "australia") { if (String.IsNullOrEmpty(postcodeString) || String.IsNullOrEmpty(stateString)) { isValid = false; } } if (!String.IsNullOrEmpty(postcodeString)) { string isNumeric = "^[0-9]+"; if (!Regex.IsMatch(postcodeString, isNumeric)) isValid = false; } return isValid; } } 

If you want to apply this to your model, you need to do this at the class level in the model (see the AttributeTargets.Class flag at the top).

Do it as follows:

 [NZPostcode("Country", "Postcode", "State")] public class UserRegistrationModel {.... 

You need to specify an attribute to check for property names. It is also possible to add client-side validation to it, but this will be an entire article in itself.

You can easily adapt the above to your scenario.

0
source

All Articles