0

Why i can't pass this model to a controller in ASP.NET MVC?

This is my View:

@model Pro.WebUI.ViewModels.DataItemVm

<div>
    <table class="table">
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.FirstSetList.FirstOrDefault().Name)
            </th>            
            <th>
                @Html.DisplayNameFor(model => model.FirstSetList.FirstOrDefault().Amount)
            </th>
        </tr>
        @foreach (var item in Model.FirstSetList)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Name)
                </td>
                <td>
                    @Html.TextBoxFor(modelItem => item.Amount)
                </td>
            </tr>
        }
    </table>
    <hr/>
    <div>
        @using (Html.BeginForm())
        {
            @Html.HiddenFor(model => model.FirstSetList)
            <input type="submit" value="Confirm"/>
        }
    </div>
</div>

After I click Confirm button - this method receives model with Count = 0;

public ActionResult FirstSet(DataItemVm model)
    {
     ...
    }

Of course my ViewModel DataItemVm has list:

public class DataItemVm
    {
     public List<FirstSetViewModel> FirstSetList { get; set; }
    }

So it looks like that problem is only at view. Maybe BeginForm should be in other place? However HiddenFor should send be enough to send this model.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
DiPix
  • 5,755
  • 15
  • 61
  • 108
  • 1
    I'm having this very same problem when my model is a Tuple. Solved it using a FormCollection as parameter for the post method – Vitor Rigoni Mar 18 '16 at 12:51
  • What kind of HTML is generated? I'm guessing `HiddenFor(model => model.FirstSetList)` doesn't know how to actually represent a list of `FirstSetViewModel` in a single hidden input. It doesn't simply serialize it or something. You probably need a create a specific edit-template for it. – Mark Mar 18 '16 at 12:54
  • You have to use `EditorFor` to render the collection – ManojAnavatti Mar 18 '16 at 13:03

1 Answers1

2

Change @foreach cycle to for - ASP.NET MVC uses indexers to generate correct ids and names for elements, so you should use @Html.TextBoxFor(x=>x.Array[index]) to correctly generate html for your collections.

This cycle:

@foreach (var item in Model.FirstSetList)
{
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.TextBoxFor(modelItem => item.Amount)
        </td>
    </tr>
}

Should instead look like this:

@for (var i = 0; i < Model.FirstSetList.Length; i++)
{
    <tr>
        <td>
            @Html.DisplayFor(model => model.FirstSetList[i].Name)
            @Html.HiddenFor(model => model.FirstSetList[i].Name) //otherwise name won't be returned to controller
        </td>
        <td>
            @Html.TextBoxFor(model=> model.FirstSetList[i].Amount)
        </td>
    </tr>
}

Another issue is - markup for the data that you want to be sent to the controller should be put inside @using (Html.BeginForm()){//put it here} block.

Check out this post about model binding in ASP.NET MVC: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

Red
  • 2,728
  • 1
  • 20
  • 22
  • 1
    Thank you! By the way you forgot surround it with beginform. Correct it if you can - it may help someday. – DiPix Mar 18 '16 at 13:19
  • @DiPix sorry, I overlooked that one, updated the post. – Red Mar 18 '16 at 13:21
  • Do you know why button is shown above table instead under Table? – DiPix Mar 18 '16 at 13:32
  • @DiPix you have probably put in inside your `` tag. If not, check your layouts using developer console in your current browser.
    – Red Mar 18 '16 at 13:39