The problem is that the expression you use in TextBoxFor and ValidationMessageFor , which MVC uses to create a string name for the field and look for validation messages from ModelState , is always the same throughout the loop iteration.
Your approach here is a bit flawed, so my answer is more complete.
1) Create view models that structurally represent the information you are trying to display.
Correct view models:
public class UserInfoViewModel { [Required (ErrorMessage="*")] public string UserName { get; set; } [Required(ErrorMessage = "*")] public string LoginName { get; set; } }
Correct your action (I do it here to illustrate the point):
public ActionResult ListOfUsers() { var users = GetUserDataRows(); // gets your collection of DataRows var model = new ListOfUsersViewModel { UsersOfList = users.Select(row = new UserViewModel { UserName = row["FirstName"], LoginName = row["UserName"] }).ToList() }; return View(model); }
2) Now you can iterate through users in your view and create the correct fields with validation messages.
Let this view ListOfUsers.cshtml . Include everything you need in your view, but use the for loop instead.
@using(Html.BeginForm("ListOfUsers")) { <ul> @for (var i = 0; i < Model.UsersOfList.Count; i++) { <li> @Html.TextBoxFor(m.UsersOfList[i].LoginName, new {@class="textbox_LoginInfoAndPermission"}) @Html.ValidationMessageFor(m => m.UsersOfList[i].LoginName) @Html.TextBoxFor(m.UsersOfList[i].UserName, new {@class="textbox_LoginInfoAndPermission"}) @Html.ValidationMessageFor(m => m.UsersOfList[i].UserName) </li> } </ul> <button type="submit">Submit changes</button> }
This will cause the HTML for each element ( 0 in the name and id will be the index of the user in the collection):
<li> <input type="text" id="UsersOfList_0_LoginName" name="UsersOfList[0].LoginName" value="..." /> <span class="field-validation-valid" data-valmsg-for="UsersOfList_0_LoginName" ... ></span> <input type="text" id="UsersOfList_0_UserName" name="UsersOfList[0].UserName" value="..." /> <span class="field-validation-valid" data-valmsg-for="UsersOfList_0_UserName" ... ></span> </li>
3) Create an action to get the submitted changes. This action will automatically bind the presented values ββto the model argument and conduct a check for you. All you have to do is check out ModelState.IsValid .
[HttpPost, ActionName("ListOfUsers")] public ActionResult ListOfUsersPost(ListOfUsersViewModel model) { // at this point, model will be instantiated, complete with UsersOfList with values submitted by the user if (ModelState.IsValid) // check to see if any users are missing required fields. if not... { // save the submitted changes, then redirect to a success page or whatever, like I do below return RedirectToAction("UsersUpdated"); } // if ModelState.IsValid is false, a required field or other validation failed. Just return the model and reuse the ListOfUsers view. Doing this will keep the values the user submitted, but also include the validation error messages so they can correct their errors and try submitting again return View("ListOfUsers", model); }