Search code examples
asp.net-mvc-3client-side-validationasp.net-mvc-validation

Validating TextBox input for a list that is a property of an MVC3 ViewModel


I realize I'm a little late to the party, but... I'm working in my first MVC project, and have been able to get a handle on most of what needs to be done. Most of the project simply reads data and pumps the data into charts. However, I have one View whose model looks like this (the parent class properties are not important here):

public class Class1 : ParentClass
{
public List<ChildClass> ChildClassList{get;set;}
}

and the ChildClass looks like this:

public class ChildClass
{
   public int Property1{get;set;}
   public int Property2{get;set;}
   public string Property3{get;set;}

   public int? ID{get;set;}
   [Editable(true)]
   public decimal? Property4{get;set;}
}

Now, retreiving the data is not an issue. I can loop through the list, and create a table for editing like this:

<% foreach(var g in Model.ChildClassList){%>
   <tr>
     <td style="text-align: right;">
    <%= Html.Label(g.Property3)%>
 </td>
     <td>
        <%=Html.TextBox(Model.ParentProperty.ToString() + "_" + g.Property2, (g.Property4.HasValue ? g.Property4.Value.ToString("C") : "$0.00"))%>
     </td>
   </tr>
<% }%>

After cruising through this site for the past couple of days, it dawned on me that I can validate the input on the server-side, in the POST method (there is a "Save" button at the bottom of the form), but (a)how do I get the validation error message back to the user, (b)perform the validation client-side?.

I must mention also that this view uses the values in the list to create a portion of a chart, prior to being rendered as a table.


Solution

  • On the server-side in the [HttpPost] action, you can check the validity of the model like this:

    [HttpPost]
    public ActionResult Save(Class1 model)
    {
       if (!ModelState.IsValid)
          return View(model);
       // Code to save model.
    }
    

    You also need to update your View to show the errors:

    <%= Html.ValidationSummary(false, "Please fix these errors.")
    <% foreach(var g in Model.ChildClassList){%>
       <tr>
         <td style="text-align: right;">
        <%= Html.Label(g.Property3)%>
     </td>
         <td>
            <%=Html.TextBox(Model.ParentProperty.ToString() + "_" + g.Property2, (g.Property4.HasValue ? g.Property4.Value.ToString("C") : "$0.00"))%>
            <%= Html.ValidationMessageFor(model => g.Property4)
         </td>
       </tr>
    <% }%>
    

    If you want to enable it client-side, you need to use unobstrusive client validation, which you can do by updating your web.config:

    <configuration>
        <appSettings>
            <add key="ClientValidationEnabled" value="true"/>
            <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
        </appSettings>
    </configuration>
    

    Also you need the following JS libraries:

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"           type="text/javascript"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js"      type="text/javascript"></script>
    <script src="//ajax.microsoft.com/ajax/jQuery.Validate/1.7/jQuery.Validate.min.js" type="text/javascript"></script>
    <script src="//ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
    

    On a side note, try and avoid loops to render out your View. It's unnecessary code soup, which can be avoided by the use of editor templates.