Consider the following Razor code
foreach(Person p in Model.Persons){
<form>
@Html.TextBoxFor(m => p.Name)
@Html.ValidationMessageFor(m => p.Name)
@Html.TextBoxFor(m => p.Surname)
@Html.ValidationMessageFor(m => p.Surname)
<button type="submit">Save</button>
</form>
}
In the processed .html
each Person
will have an identical name
attribute with each other. This leads to a wrong behaviour when the validation does not succeed: each Person will have an error message even if I was editing only one of them.
What would be the best way to resolve this issue?
My Post handler is as follows
[HttpPost]
public IActionResult SavePerson(Person person){
// ...
}
and it'd be great to leave it as it is.
The reason why the validation error will show for all input textbox is Html.TextBoxFor
and Html.ValidationMessageFor
helpers generate HTML elements with the same name attributes for each Person in the list. This results in validation messages being shown for all items when only one item is edited and validation fails.
To solve this issue, I suggest you could consider create a partial views to split each Person form and handle the submit individually.
More details, you could refer to below example:
1.Create a partial views inside the shared view folder:
@model Person
<form asp-action="SavePerson" method="post">
@Html.HiddenFor(m => m.Id)
<label for="Name">Name</label>
@Html.TextBoxFor(m => m.Name)
@Html.ValidationMessageFor(m => m.Name)
<label for="Surname">Surname</label>
@Html.TextBoxFor(m => m.Surname)
@Html.ValidationMessageFor(m => m.Surname)
<button type="submit">Save</button>
</form>
2.Use it inside the view:
@foreach (var person in Model.Persons)
{
@await Html.PartialAsync("_PersonForm", person)
}
Result:
Post method:
My whole test sample:
Person model:
public class Person
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Surname { get; set; }
}
Home controller:
public IActionResult Index()
{
List<Person> people = new List<Person>() { new Person { Id=1, Name="test1", Surname="test1" }, new Person { Id = 2, Name = "test2", Surname = "test2" } };
return View(people);
}
[HttpPost]
public IActionResult SavePerson(Person person)
{
if (ModelState.IsValid)
{
// Save the person data to the database or perform necessary operations
return RedirectToAction("Index");
}
return View(person);
}
View:
@{
ViewData["Title"] = "Home Page";
}
@model List<Person>
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
<><hr/>
@foreach (var person in Model)
{
@await Html.PartialAsync("_PersonForm", person)
}
@section scripts {
<partial name="_ValidationScriptsPartial" />
}
Test result:
It works at myside, each submit button works for each form.