-2

Hi I want to grab all user modify data.

My question is why controller can't receive the model data from View in my project.

Please explain why this error was caused and how to solve it.

Models:

 public class ShoppingCart
    {
        public List<ShoppingCartItemModel> items = new List<ShoppingCartItemModel>();

        public IEnumerable<ShoppingCartItemModel> Items
        {
            get { return items; }
        }
    }

  public class ShoppingCartItemModel
    {
        public Product Product
        {
            get;
            set;
        }

        public int Quantity { get; set; }
    }

Controller

 [HttpPost]
        public RedirectToRouteResult EditFromCart(ShoppingCart MyModel)
        {
            ShoppingCart cart = GetCart();

            foreach (var CartItem in cart.items)
            {
                foreach (var ReceiveModelItem in MyModel.items)
                {
                    if (CartItem.Product.ProductID == ReceiveModelItem.Product.ProductID)
                    {
                        CartItem.Quantity = ReceiveModelItem.Quantity;
                    }
                }
            }

            return RedirectToAction("Index", "ShoppingCart");

        }

View

@model ShoppingCart

@{
    ViewBag.Title = "購物車內容";
}

<h2>Index</h2>

<table class="table">
    <thead>
        <tr>
            <th>
                Quantity
            </th>
            <th>
                Item
            </th>
            <th class="text-right">
                Price
            </th>
            <th class="text-right">
                Subtotal
            </th>
        </tr>
    </thead>
    <tbody>
        @using (Html.BeginForm("EditFromCart", "ShoppingCart", FormMethod.Post))
        {
            foreach (var item in Model.items)
            {
                <tr>
                    <td class="text-center">
                        @item.Product.ProductName
                    </td>
                    <td class="text-center">
                        @item.Product.Price.ToString("c")
                    </td>
                    <td class="text-center">
                        @( (item.Quantity * item.Product.Price).ToString("c"))
                    </td>
                    <td class="text-left">

                        @Html.EditorFor(model => item.Quantity, null, "UserInputQuantity")

                        @Html.Hidden("ProductId", item.Product.ProductID)
                    </td>

                </tr>
            }
            <tr>
                <td colspan="3">
                    <input class="btn btn-warning" type="submit" value="Edit">
                </td>
            </tr>
        }
    </tbody>
</table>
Melo Tang
  • 23
  • 8
  • If you need another information please tell me – Melo Tang Sep 30 '16 at 07:32
  • having a list of items ( list of entities , in this cause shopping item in a cart) cannot be submitted back to a controller with simple MVC / Razor. you will need to use JavaScript to maintain the list and post it back as json etc. there are a lot ot articles on the web regarding ho to develop MVC cart – Emil Sep 30 '16 at 09:01
  • @Emil of course you can! You just need to index them properly. The model binder can bind collections and lists too. – juunas Sep 30 '16 at 11:03

2 Answers2

2

You must explicitly create a hidden input for each property in your complex object that you want to be bound. IEnumerables and binding don't play very nicely directly out of the box - it looks like MVC has better base support for IList<> and arrays, but you'll still have to enumerate the collection and create hidden inputs for each item. Have a look at this link. So, ideally your view should be:

@model ShoppingCart

@{
    ViewBag.Title = "購物車內容";
}

<h2>Index</h2>

<table class="table">
    <thead>
        <tr>
            <th>
                Quantity
            </th>
            <th>
                Item
            </th>
            <th class="text-right">
                Price
            </th>
            <th class="text-right">
                Subtotal
            </th>
        </tr>
    </thead>
    <tbody>
        @using (Html.BeginForm("EditFromCart", "ShoppingCart", FormMethod.Post))
        {
            for (int i = 0; i < Model.items.Count(); ++i)
            {
                <tr>
                    <td class="text-center">
                        @Model.items[i].Product.ProductName

                    </td>
                    <td class="text-center">
                        @Model.items[i].Product.Price.ToString("c")

                    </td>
                    <td class="text-center">
                        @( (Model.items[i].Quantity * Model.items[i].Product.Price).ToString("c"))

                    </td>
                    <td class="text-left">

                        @Html.EditorFor(model => Model.items[i].Quantity)


                        @Html.HiddenFor(model => Model.items[i].Product.ProductID)
                        @Html.HiddenFor(model => Model.items[i].Product.ProductName)
                        @Html.HiddenFor(model => Model.items[i].Product.Price)

                    </td>

                </tr>
            }
            <tr>
                <td colspan="3">
                    <input class="btn btn-warning" type="submit" value="Edit">
                </td>
            </tr>
        }
    </tbody>
</table>
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
Ajay
  • 643
  • 2
  • 10
  • 27
0

Names are not correctly set for your text and hidden inputs:

@Html.EditorFor(model => item.Quantity, null, "UserInputQuantity")

@Html.Hidden("ProductId", item.Product.ProductID)

If you inspect elements you can see names are UserInputQuantity and ProductId, but they should be items[i].Quantity and items[i].Product.ProductID respectively.

You can take a look at this link: MVC Model binding of complex objects

Community
  • 1
  • 1
Gohar
  • 43
  • 1
  • 7