40

Say I have the following models:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Town
{
    public string Name { get; set; }
    public IEnumerable<Person> People { get; set; }
}

Then, in my Razor view, I have this:

@model Town
@using(Html.BeginForm())
{
    <table>
        @foreach(var person in Model.People)
        {
            <tr>
                <td>@Html.TextBoxFor(m => person.Name)</td>
                <td>@Html.TextBoxFor(m => person.Age)</td>
            </tr>
        }
    <table>
    <input type="submit" />
}

Then, I have an action for the POST, something like this:

[HttpPost]
public ActionResult Index(Town theTown)
{
    //....
}

When I post, the IEnumerable<Person> does not come across. If I look at it in Fiddler, the collection only posts once, and doesn't enumerate the collection, so I get:

People.Name = "whatever"
People.Age = 99

However, if I change People to an IList and use a for loop instead of a foreach...

@for(var i = 0;i < Model.People.Count;i++)
{
    <tr>
        <td>@Html.TextBoxFor(m => Model.People[i].Name)</td>
        <td>@Html.TextBoxFor(m => Model.People[i].Age)</td>
    </tr>
}

It works. Am I doing something wrong? What am I missing?

1
  • 3
    This is normal behavior. The model binder uses the name property of the input elements from the rendered html. Using a for loop with an indexer is the only way to have unique names that the model binder can associate to the model Commented Jan 4, 2013 at 22:00

2 Answers 2

62

the problem is not with the IEnumerable or the IList it the way you are rendering the collection in your view.

@for(var i = 0;i < Model.People.Count;i++)
{
    <tr>
        <td>@Html.TextBoxFor(m => Model.People[i].Name)</td>
        <td>@Html.TextBoxFor(m => Model.People[i].Age)</td>
    </tr>
}

Observe that with each list item you are appending a continuous index which enables the model binder to do its magic

A good read

Sign up to request clarification or add additional context in comments.

1 Comment

This will not work on an Generic.IEnumerable collection so you will need to change your collection to some form of an indexable collection.
0

All you missed was placing var instead of the Model itself(People) like below

<table>
@foreach(People person in Model.People)
{
<tr>
<td>@Html.TextBoxFor(m => person.Name)</td>
<td>@Html.TextBoxFor(m => person.Age)</td>
</tr>
}
<table>
<input type="submit" />

3 Comments

Wont work for post requests as the json deserializer will not be able to match these properties to the fields.
It is working but every input form has same name and same value.
@nam means in razor view the loop is working and generating it's corresponding html elements. But every "name" input field id and name is "name" and every "age" input field id and name is "age"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.