ViewModel collection property lost values after posting back to controller action in MVC 3
Asked Answered
S

3

8

I have my view models :

public class POReceiptViewModel
{
    public virtual int PONumber { get; set; }
    public virtual string VendorCode { get; set; }

    public virtual IList<POReceiptItemViewModel> POReceiptItems { get; set; }

    public POReceiptViewModel()        
    {
        POReceiptItems = new List<POReceiptItemViewModel>();
    }
}

public class POReceiptItemViewModel
{
    public virtual string ItemCode { get; set; }
    public virtual string ItemDesription { get; set; }
    public virtual decimal OrderedQuantity { get; set; }
    public virtual decimal ReceivedQuantity { get; set; }
    public virtual DateTime ReceivedDate { get; set; }

    public POReceiptItemViewModel()
    {
        ReceivedDate = DateTime.Now;
    }
}

Then my controller has two actions, one get and one post:

public ActionResult CreatePOReceipt(int poNumber)
{
    PurchaseOrder po = PurchasingService.GetPurchaseOrder(poNumber);
    POReceiptViewModel poReceiptViewModel = ModelBuilder.POToPOReceiptViewModel(po);
    return View("CreatePOReceipt", poReceiptViewModel);
}

[HttpPost]
public ActionResult CreatePOReceipt(POReceiptViewModel poReceiptViewModel)
{
    // Here the problem goes. The items in the poReceiptViewModel.POReceiptItems has lost. the count became zero.
    return View("Index");
}

And in my View, I can display the model properly and by using @Html.HiddenFor<> I can persist view model data as I wanted to. But not on the List<> navigation property.

@model POReceiptViewModel

@using (Html.BeginForm())
{   
    <fieldset>
        <legend>Purchase Order</legend>
        <label>For PO # :</label>
        @Html.HiddenFor(m => m.PONumber)    
        @Html.DisplayTextFor(m => m.PONumber)
        <label>Vendor Code :</label>
        @Html.HiddenFor(m => m.VendorCode)  
        @Html.DisplayTextFor(m => m.VendorCode)
    </fieldset>

    <fieldset>
        <legend>Received Items</legend>

        <table class="tbl" id="tbl">
           <thead>
           <tr>
           <th>Item Code</th><th>Item Description</th><th>OrderedQuantity</th><th>Received Quantity</th><th>Received Date</th>
           </tr>
           </thead>
           <tbody>
           @Html.HiddenFor(m => m.POReceiptItems) // I'm not really sure if this is valid
           @if (Model.POReceiptItems.Count > 0)
            {
                foreach (var item in Model.POReceiptItems)
                {       
                    <tr>
                        <td>@Html.DisplayTextFor(i => item.ItemCode)</td>@Html.HiddenFor(i => item.ItemCode)    
                        <td>@Html.DisplayTextFor(i => item.ItemDesription)</td>@Html.HiddenFor(i => item.ItemDesription)    
                        <td>@Html.DisplayTextFor(i => item.OrderedQuantity)</td>@Html.HiddenFor(i => item.OrderedQuantity)  
                        <td>@Html.TextBoxFor(i => item.ReceivedQuantity)</td>
                        <td>@Html.TextBoxFor(i => item.ReceivedDate)</td>
                    </tr>
                }
            }
           </tbody>
        </table>
    </fieldset>
    <input type="submit" name="Received" value="Received" />
}

PROBLEM: POReceiptItems lost when the form submitted. As much as possible I don't want to use TempData["POReceiptItems"] = Model.POReceiptItems but even if I use it, the value entered into ReceivedQuantity and ReceivedDate are not save into the TempData.

Thanks in advance!

Sirajuddaula answered 10/3, 2012 at 13:4 Comment(0)
T
10

try

@for (int i = 0; i < Model.POReceiptItems.Count(); i++)
{ 
<tr>
  <td>@Html.DisplayTextFor(m => m.POReceiptItems[i].ItemCode)</td>@Html.HiddenFor(m => m.POReceiptItems[i].ItemCode)    
  <td>@Html.DisplayTextFor(m => m.POReceiptItems[i].ItemDesription)</td>@Html.HiddenFor(m => m.POReceiptItems.ItemDesription)                                                               <td>@Html.DisplayTextFor(m => m.POReceiptItems[i].OrderedQuantity)</td>@Html.HiddenFor(m => m.POReceiptItems[i].OrderedQuantity)  
  <td>@Html.TextBoxFor(m => m.POReceiptItems[i].ReceivedQuantity)</td>
  <td>@Html.TextBoxFor(m => m.POReceiptItems[i].ReceivedDate)</td>
</tr>
}

also read this blog post to understand how model binding to a list works

Tendinous answered 10/3, 2012 at 13:17 Comment(1)
Perfect! Providing solution then providing additional reading is awesome! It's working now the way I expect it. I must read the blog to further understand it as I am new to mvc. fyi, this is my first post here in stackoverflow and i got an answer in few minutes.Sirajuddaula
B
0

You lose your list because MVC don't handle the List the way you think.

You should use BeginCollectionItem look at this post

Blackman answered 10/3, 2012 at 13:10 Comment(0)
F
0

I had a similar problem, the "List" attribute returned without values(count = 0), I tried different ways and answers and nither works. Then I tried by myself and now it is working, this is my solution:

I send an object with some normal attributes and a "List", after that I used the normal attributes and my "list" in a For. In my controller (Post ActionResult), in the parameters section I added two parameters, my original object and my "List" as second parameter and it works!!! I hope this helps you and others with similar problems.

Factotum answered 7/10, 2017 at 23:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.