boilers222
boilers222

Reputation: 1989

Model not being updated when using a List

I have a model with a property of type List. I use this property to show values on my view. I use a foreach loop to go through each item in the list and displaying them using DisplayFor and TextBoxFor. That part is working fine; I've used TextBoxFor before and any user entered text gets past to the model on submit. However, when using a list, the list is null when the form is submitted. All the other properties in the model are updated and I can access them correctly. What is preventing the list from binding and how can I fix this?

ModelInstrumentListingDetail

public class ModelInstrumentListingDetail
{
    public int InstrumentTagID { get; set; }
    public string InstrumentTagDescription { get; set; }

    public List<ModelInstrumentListingItem> items { get; set; }
}

ModelInstrumentListingItem

public class ModelInstrumentListingItem
{
    public string Field { get; set; }
    public string Label { get; set; }
}

View

@model GPC.Models.ModelInstrumentListingDetail

@using (Html.BeginForm("InstrumentListingAdd", "Home", FormMethod.Post, new { id = "InstrumentListingDetailForm" }))
{
  <table>
   <tr>
    <td>
         @Html.TextBoxFor(m => m.InstrumentTagDescription)
    </td>
   </tr>

  @foreach (GPC.Models.ModelInstrumentListingItem item in Model.items)
  {
   <tr>
      <td>
          @Html.DisplayFor(m => item.Label)
      </td>
      <td>
          @Html.TextBoxFor(m => item.Field)
      </td>
   </tr>
   }
</table>
<input id="submitInstrumentListingAdd" name="submitInstrumentListingAdd" value="Add" type="submit" class="SaveButton" />
}

Controller

[HttpPost]
public ActionResult InstrumentListingAdd(ModelInstrumentListingDetail model, string submitInstrumentListingAdd)
{
  ...
}

On submit, the model posted to the controller has InstrumentDescription with a value, but items is null. I need to figure out how to fill items with the new values.

Upvotes: 0

Views: 1139

Answers (3)

teo van kot
teo van kot

Reputation: 12491

You should use either EditorTemplates and EditorFor helper or for loop if you want to bind your list right. Here is an example.

If you will use for loop it should be like this:

  @for (int i = 0; i< Model.items.Count(); i++)
  {
   <tr>
      <td>
          @Html.DisplayFor(m => Model.items[i].Label)
      </td>
      <td>
          @Html.TextBoxFor(m => Model.items[i].Field)
      </td>
   </tr>
   }

for loop - short way, but using EditorTemplate - more clean solution, so I recommend it.

Upvotes: 1

Jason Evans
Jason Evans

Reputation: 29186

Change the loop like so:

@for(int idx = 0;idx < Model.items.Count;idx++)
{
    <tr>
         <td>
            @Html.DisplayFor(_ => Model.items[idx].Label)
         </td>
         <td>
             @Html.TextBoxFor(_ => Model.items[idx].Field)
         </td>
     </tr>
}

The reason this works is that the <input> elements will be generated like so:

<input id="Items_0_" name="Items[0]" type="text" value="Foo"> <input id="Items_1_" name="Items[1]" type="text" value="Bar">

When you POST the data, something like the following will be in the body:

Items[0]:Foo
Items[1]:Bar

The default ASP.NET MVC model binder will pick these Items up from the request body and apply them to the viewmodel, in your case ModelInstrumentListingDetail.items

Upvotes: 3

FrostyStraw
FrostyStraw

Reputation: 1656

I think I had a similar problem earlier.

Maybe try:

[HttpPost]
public ActionResult InstrumentListingAdd([Bind(Prefix = "item")]ModelInstrumentListingItem model, string submitInstrumentListingAdd)
{
  ...
}

Upvotes: 0

Related Questions