This question already has an answer here:
- How to pass IEnumerable list to controller in MVC including checkbox state? 1 answer
All, please clear up my confusion on how the model binding works with IEnumerables and Editor Templates.
I have a view, Approve.cshtml
@model IEnumerable<MvcWebsite.Models.Approve>
<table>
<tr>
<th>
Name
</th>
</tr>
@Html.EditorForModel()
</table>
A model, Approve.cs
public class Approve
{
public string Name { get;set;}
public string Role { get; set; }
}
And an editor template
@model MvcWebsite.Models.Approve
@using (Html.BeginForm("Approve", "Registration", FormMethod.Post))
{
<tr>
<td>
@Html.HiddenFor(m => m.Name)
@Html.EditorFor(m => m.Role)
</td>
<td>
<input type="submit" value="Approve" class="submit-button" />
</td>
</tr>
}
This is all fine and good. It renders the following output.
<input name="[0].Name" type="hidden" value="" />
....
However, in my Controller, I can't seem to receive values back for the Model (binding).
[HttpPost]
public ActionResult Approve(Approve approveModel)
{
.... approveModel has all default values
}
Can someone shed light on what I am doing wrong here? I abbreviated the code, I am using the Editor Template with other EditorFor and HiddenFor fields from my model...
Edited: I basically have a table layout, each with the User's Name, a textbox where I can enter their role (User or Admin) and then an Approve button which submits to my controller. Hence the reason I want to only return a single Approve object. I can return the entire IEnumerable to my Controller, but if I do that, how can I tell which of the items was the one I clicked the Approve button (submit) for?
EDIT: So I have modified the code so that I have a single form surrounding my entire View Approve.cshtml
@model IEnumerable<MvcWebsite.Models.Approve>
@using (Html.BeginForm("Approve", "Program", FormMethod.Post))
{
<table>
<tr>
<th>
Name
</th>
</tr>
@Html.EditorForModel()
</table>
}
And then changed the controller to
[HttpPost]
public ActionResult Approve(IEnumerable<Approve> approvals)
{
// ???????????????????????
}
Now I'm still not clear on how to know which row I clicked Approve for. I know there are other ways to accomplish this task (create a checkbox for approve, and approve anything checked, etc.) However, I need the ability to click a button and only save 1 row back to the database, regardless if the user entered information into the other rows. Is it better practice to wrap my IEnumerable inside of it's own model (i.e. AllApprovals) and then add helper properties to that parent model (SelectedIndex, etc.)? If that is the approach to take, then how do I set the SelectedIndex after clicking an Approve button? Is that still jquery magic or is there a correct MVC way to accomplish this? Jquery magic seems very hackish to me?
EDIT: Based on Brian's response, here is my final. Still doesn't feel quite right, but it works!
View
@model IEnumerable<MvcWebsite.Models.Approve>
<table>
<tr>
<th>
Name
</th>
</tr>
@Html.EditorForModel()
</table>
Editor Template
@using (Html.BeginForm("Approve", "Registration", FormMethod.Post))
{
<tr>
<td>
@Html.HiddenFor(m => m.Name)
@Html.EditorFor(m => m.Role)
</td>
<td>
<input type="submit" value="Approve" class="submit-button" />
</td>
</tr>
}
Controller
[HttpPost]
public ActionResult Approve([Bind(Prefix="approval")]Approve approval) {
// WORKS!
}