39

I have a model:

public class MyListModel
{
    public int ID {get;set;}
    public List<User> Users{get;set;}
}

How do I use the Html.EditorFor method inside a foreach?

@model MyListModel
<table>
  <tr>
    <th></th>
  </tr>
  @foreach (var item in Model.Users) {
     <tr>
       <td>
          @Html.EditorFor(item.Enabled)
       </td>
     </tr>
  }
</table>
Jeremy
  • 44,950
  • 68
  • 206
  • 332

3 Answers3

67
@Html.EditorFor(x=> item.Enabled)

It's been pointed out many times that posting such a model back to server will not work in mvc by default. For properly editing with EditorFor in a loop - for should be used as in:

 @for(var i = 0; i< Model.Users.Count;i++){
      Html.EditorFor(i=>Model.Users[i])
 }
Alexander Taran
  • 6,655
  • 2
  • 39
  • 60
  • 4
    Definitely works. The "right hand side" of a lambda does not have to reference the "left hand side". – Eilon Jan 01 '10 at 00:40
  • Well gee, would you look at that! That will clean up some of the Html.RenderPartial()s I've been using unnecessarily. – Nathan Taylor Jan 01 '10 at 00:49
  • You're right, it does work. I didn't think it would either. Thanks. – Jeremy Jan 01 '10 at 00:52
  • 6
    Keep in mind that lambdas are just method definition. A method can take a parameter "x" and not actually use it in the method body. A neat trick, for sure! I highly recommend reading Brad Wilson's 5-part series on templated helpers: http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html – Eilon Jan 01 '10 at 00:53
  • 1
    I never realized that about lambdas; where have I been all this time?! – Nathan Taylor Jan 01 '10 at 00:54
  • So in this case, x is a parameter of the method definition, item.enabled is the body, what type is x? – Jeremy Jan 05 '13 at 03:47
  • x is of the same type as model. – Alexander Taran Jan 09 '13 at 10:16
  • 8
    Note that this will cause all elements created by the EditorFor to have the same name and Id. It's not valid for multiple elements to share the same Id. – ChadT Apr 11 '13 at 23:54
  • 2
    This will work to display the properties, but it *will not* bind properly on postback for the reason that @DaRKoN_ mentioned. The DefaultModelBinder has no idea how to bind the unindexed properties with duplicate names. The names are what MVC uses to map the values from the request to the properties of your model. – joelmdev Oct 02 '13 at 13:48
  • 2
    This solution is working, but will lost the bindings when you post the form back to the server. So the best method is to use a simple for loop. – martonx Dec 03 '14 at 13:07
  • Not really sure why this is the accepted answer if it loses bindings when posted back to the server. – Manachi Apr 05 '18 at 01:56
15
@for (var i = 0; i < Model.Users.Count; i++)
{
<tr>
    <td>@Html.EditorFor(model => model.Users[i].Enabled)</td>
    <td>@Html.EditorFor(model => model.Users[i].FirstName)</td>
    <td>@Html.EditorFor(model => model.Users[i].LastName)</td>
</tr>
}

Plus some hidden variables for at least one property of the User are required:

@for (var i = 0; i < Model.Users.Count; i++)
{
    @Html.HiddenFor(model => model.Users[i].FirstName)
}

Not what you would call elegant but it works with respect to binding in your post action.

Jamie
  • 779
  • 1
  • 9
  • 17
1

Is there any other reason (example apart) for explicitly using the foreach yourself? You could make a Custom Editor (or Display) helper for User class and make @Html.EditorFor(model=>model.Users). Razor will use the foreach internally for processing each element with your Custom Helper.

Just an idea for those visiting the question with really no clue how manage this cases.

David Silva-Barrera
  • 1,006
  • 8
  • 12