I am constructing a page using Editor Templates and composition. My view model contains properties which are themselves view models. E.g.
public class ParentModel
{
public boolean SomeCheckBox { get; set; }
public ChildModel Child { get; set; }
}
public class ChildModel
{
[Required]
public string SomeString { get; set; }
[Required]
public string SomeOtherString { get; set; }
}
I would like the data annotation validation to kick in on the child only if the property SomeCheckBox on the parent is true.
I’ve seen a RequiredIf custom validation attribute elsewhere on stackoverflow, however it only works when the condition is a value of the same view model. I need something that can check the parent, or indeed a property on an ancestor.
My temporary hack is to clear the ModelState errors on postback if the checkbox isn’t true.
I’ve also had to write some custom javascript so that the client browser suppresses the validation if the checkbox isn’t ticked.
The real example is much more complicated than this but hopefully it’s clear from the above simplified example what I’m after.
What would be nice is an attribute on the parent view model that is something like
public class ParentModel
{
public boolean SomeCheckBox { get; set; }
[SuppressValidationIf("SomeCheckBox", false)]
public ChildModel Child { get; set; }
}
Any ideas?
This excellent example perfectly illustrates the limitations of doing declarative validation which is what data annotations are.
It’s for this reason that I would recommend you using an imperative approach for your validation rules as you can handle many scenarios. FluentValidation.NET is a great example of a library which would have rendered this validation scenario a piece of cake.
Let me illustrate how it could handle this scenario:
We start by defining validators for our child and parent models:
Notice how the child validator is included based on the value of the
SomeCheckBoxproperty on the parent? Now your models would look like this:And that’s all.
You simply install the
FluentValidation.MVC3NuGet, add the following line inApplication_Start:and now you work as usual:
and a view:
If the checkbox is checked the child validator will kick in and require the 2 properties.