title: MVC3 Validation for controls in a loop
body: <p>In my View, I'm making an entire html table editable.  Each field in the table has validation.  Here is some sample code...</p>
  
  <pre><code>&lt;tbody&gt;
      foreach (Item item in Model.Items)
      {
          &lt;tr&gt;
              &lt;td&gt;
                  @Html.TextBoxFor(x =&gt; em.Value)
                  @Html.ValidationMessageFor(x =&gt; em.Value)
              &lt;/td&gt;
          &lt;/tr&gt;
      }
  &lt;/tbody&gt;
  </code></pre>
  
  <p>This is creating two problems on the browser.  </p>
  
  <p>1)  Since the name attribute for all the  controls are the same, when one field is invalid, the error messages are displayed on all fields of the same name.</p>
  
  <p>2)  Probably related to the names as well, when validating the form, if the  control in the first row is invalid, the form is invalid.  But  controls in all other rows will not invalidate the form (even though the error messages are displayed).</p>
  
  <pre><code>if (!$(form).valid()) {
      return false;
  }
  </code></pre>
  
  <p>Any thoughts would be helpful. </p>
  
  <p><strong>UPDATE: THE SOLUTION</strong></p>
  
  <p>Per bobek suggestion, I created custom extensions for TextBoxInLoopFor and ValidationMessageInLoop.  Below is the solution:</p>
  
  <pre><code>public static MvcHtmlString TextBoxInLoopFor&lt;TModel, IItem, TValue&gt;(this HtmlHelper&lt;TModel&gt; html, Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression, IItem item, object htmlAttributes)
  {
      var model = item as IInLoopForModel; 
      if (model == null)
          return MvcHtmlString.Empty; 
  
      var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
      var fieldName = ExpressionHelper.GetExpressionText(expression);
      var name = model.Name + fieldName;
  
      var tag = new TagBuilder("input");
      tag.MergeAttributes(new RouteValueDictionary(htmlAttributes));
      tag.Attributes.Add("id", name);
      tag.Attributes.Add("for", name);
      tag.Attributes.Add("name", name); 
      tag.Attributes.Add("value", metadata.Model.ToString());
  
      // Add the validation attributes
      ModelState modelState;
      if (html.ViewData.ModelState.TryGetValue(name, out modelState))
      {
          if (modelState.Errors.Count &gt; 0)
              tag.AddCssClass(HtmlHelper.ValidationInputCssClassName);
      }
      tag.MergeAttributes(html.GetUnobtrusiveValidationAttributes(name, metadata));
  
      return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
  }
  
  public static MvcHtmlString ValidationMessageInLoopFor&lt;TModel, IItem, TValue&gt;(this HtmlHelper&lt;TModel&gt; html, Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression, IItem item)
  {
          var model = item as IInLoopForModel;
      if (model == null)
          return MvcHtmlString.Empty;
  
      var fieldName = ExpressionHelper.GetExpressionText(expression);
      var name = model.Name + fieldName;
  
      var tag = new TagBuilder("span");
      tag.Attributes.Add("class", "field-validation-valid");
      tag.Attributes.Add("data-valmsg-replace", "true");
      tag.Attributes.Add("data-valmsg-for", name);
      return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
  }
  </code></pre>