0

I've got the following page trying to send back the data in the model. At the moment, I only want to return the model in an unmanipulated state just to see that I get back whatever I've sent out to the client.

@model List<UserSetting>
@using (Html.BeginForm("SaveSettings", "Account", Model, FormMethod.Post))
{
  <table>
    <tr>
      <th>User name</th>
      <th>Setting</th>
      <th>Value</th>
      <th>Order</th>
    </tr>
    @foreach (UserSetting setting in Model)
    {
      <tr>
        <td>@setting.User.UserName</td>
        <td>@setting.Name</td>
        <td>@setting.Value</td>
        <td>@setting.Order</td>
      </tr>
    }
  </table>
  <input type="submit" />
}

However, the object received in the controller is empty. It's not null, so it seems that I'm posting back something but for some reason, that something contains zero elements.

[HttpPost]
public void SaveSettings(List<UserSetting> settings) { ... }

What am I missing and how do I troubleshoot it? I have the sensation that it's something really easy and that I'll feel really stupid when someone points that out to me.

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • Your not generating any form controls (`` etc). A form only sends back the values of its successful form controls. And you cannot use a `foreach` loop to generate form controls for a collection anyway - refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) –  Aug 29 '16 at 12:40
  • Also, be sure to check [BeginCollectionItem](https://github.com/danludwig/BeginCollectionItem) out. – Adil Mammadov Aug 29 '16 at 13:07

2 Answers2

4

You just display items, which doesn't magically create hidden inputs (which are needed to get data in your form).

By the way, rather use @Html.DisplayFor to... display, this will manage some null checks for you.

And you need a for loop, it won't work with foreach, as stated in Stephen Muecke's comment.

So

@for(var i = 0; i < Model.Count; i++)
    {
      <tr>
        <td>@Html.HiddenFor(m => Model[i].User.UserName) @Html.DisplayFor(m => Model[i].User.UserName)</td>
        <td>@Html.HiddenFor(m => Model[i].Name) @Html.DisplayFor(m => Model[i].Name)</td>
        <td>@Html.HiddenFor(m => Model[i].Value) @Html.DisplayFor(m => Model[i].Value)</td>
        <td>@Html.HiddenFor(m => Model[i].Order) @Html.DisplayFor(m => Model[i].Order)</td>
      </tr>
    }

of course, if you wanna edit your datas, you can replace the

@Html.HiddenFor(m=> Model[i].xxx) @Html.DisplayFor(m => Model[i].xxx)

by

@Html.TextBoxFor(m => Model[i].xxx)
Raphaël Althaus
  • 59,727
  • 6
  • 96
  • 122
1

You've got two issues in your code. First is addressed by @RaphaelAlthaus but the second is that you're implicitly specifying the model to be sent back. I skipped that in BeginForm constructor and it works.

@using (Html.BeginForm("SaveSettings", "Account", FormMethod.Post))
{
  <table>
    <tr>
      <th>Value</th>
    </tr>
    @for (int i = 0; i < Model.Count; i++)
    {
      <tr>
        <td>@Html.TextBoxFor(_ => Model[i].Value)</td>
      </tr>
    }
  </table>
  <input type="submit" />
}