Overview of the problem:
I want to have some conditional logic in my form. The user makes a choice with a radio button and depending on the selection I want to hide some fields and show some other fields. This should also affect validation (hidden fields shouldn't be validated). I think this is a typical problem, but I couldn't find any examples and my own solution seems to have a lot of plumbing.
My actual problem:
Let's start with the viewmodel classes (somewhat simplified for the needs of this question):
public class Scenario
{
public Request Request { get; set; }
public Response Response { get; set; }
// … some other properties
}
public class Request
{
//some properties
}
public class Response
{
[Required]
public string ResponseType { get; set; }
[Required]
public string State { get; set; }
[Required]
[NotZero] //this is my custom validation attribute
public string ErrorCode { get; set; }
public string ErrorDescr { get; set; }
}
In my create/edit view for the Scenario model I have a rather big form consisting of 3 tabs. On the 3rd tab I display a partial view based on the Response model. This is where I want the conditional logic. ResponseType property is the radio button on the form. It can have two values: NORMAL and ERROR. In the case of ERROR I want to display and validate ErrorCode and ErrorDescr properties. In the case of NORMAL I want to display and validate only the State property.
My solution:
- In the Response partial view I have some jquery .hide() and .show() calls hooked up to hide/show relevant input elements.
- I modified jquery unobtrusive validation script to stop it from validating hidden fields ( http://blog.waynebrantley.com/2011/01/mvc3-validates-hidden-fields-using.html )
In the Scenario controller I have code like this:
public ActionResult Edit(int id, Scenario scenario) { Response response=scenario.Response; if (response.ResponseType != null) { if (response.ResponseType == "NORMAL") { //in this case remove validation for errorcode this.ModelState.Remove("Response.ErrorCode"); } else { //in this case remove validation for state this.ModelState.Remove("Response.State"); } } if (ModelState.IsValid) { //map to entity and save to database } }
This is a whole lot of ugly plumbing (especially the controller code - removing items from ModelState with a string key... no type safety etc), surely there must be a better way?