1

I have a project to make an online shop between users (post a product, buy, etc.) using a database. In this project I have a view called "ShoppingCart":

@model IEnumerable<MyFirstProject.Models.Product>

@{
    ViewBag.Title = "ShoppingCart";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Your Shopping Cart</h2>



@if (Model == null)
{
    <div style="float:left">Your cart is empty.</div>
    <div>
        Total payment: 0
    </div>
}
else
{
    decimal tPrice = 0;
    <div>
    <table style="float:left">
        @foreach (var product in Model)
        {
            tPrice = tPrice + product.Price;
            { Html.RenderPartial("ProductLine", product);}
        }
    </table>
        </div>
    <div>
        Total payment: @tPrice
    </div>
}

It receives a list of products which the user decided to buy and displays them (not the important part). I need to add a button which will send the list to an action result in the "ShoppingController":

[HttpPost]
        public ActionResult ShoppingCart(List<Product> bought)
        {
            if (ModelState.IsValid)
            {
                foreach (var listP in bought.ToList())
                {
                    foreach (var databaseP in db.Products.ToList())
                    {
                        if (listP.ProductID == databaseP.ProductID)
                        {
                            databaseP.State = 1;
                            db.SaveChanges();
                            break;
                        }
                    }
                }
                return RedirectToAction("Index");
            }

            else
            {
                return View(bought);
            }
        }

"State" indicates if the product was bought or not (0=not bought, 1=bought), db is the database

  • You don't. (you would need to include a form control for every property of every product in you view). If this is a confirmation page, then you just post a ID value and then retrieve the collection of products the user has already selected and retrieve it from the repository you previously stored it (I assume you used `Session`?) –  Dec 18 '15 at 22:54

1 Answers1

0

If you wan't to post any data from a view to an action method, you should keep that data in form elements and keep that in a form. Since you want to post a collection of items, You may use Editor Templates.

Let's start by creating a view model.

public class ShoppingCartViewModel
{
    public decimal TotalPrice { set; get; }
    public List<Product> CartItems { set; get; }
}

public class Product
{
    public int Id { set; get; }
    public string Name { set; get; }
}

Now in your GET action, you will create an object of the ShoppingCartViewModel, load the CartItems property and send to the view.

public ActionResult Index()
{
    var cart = new ShoppingCartViewModel
    {
        CartItems = new List<Product>
        {
            new Product   { Id = 1, Name = "Iphone" },
            new Product   { Id = 3, Name = "MacBookPro" }
        },
        TotalPrice = 3234.95
    };
    return View(cart);
}

Now i will create an EditorTemplate. To do that, Go to your ~/Views/YourControllerName folder, and Create a directory called EditorTemplates and add a view with name Product.cshtml

The name of the file should match with the name of the type.

enter image description here

Open this new view and add the below code.

@model YourNamespace.Product
<div>
    <h4>@Model.Name</h4>
    @Html.HiddenFor(s=>s.Id)
</div>

You can keep the display however you want. But the important thing is, We need to keep a form field for the productId. We are keeping that in a hidden field here.

Now let's go back to our main view. We need to make this view strongly typed to our ShoppingCartViewModel. We will use the EditorFor html helper method in this view to call our editor template

@model ReplaceYourNamespaceHere.ShoppingCartViewModel
@using (Html.BeginForm())
{       
    @Html.EditorFor(x => x.CartItems)
    <p>Total : @Model.TotalPrice</p>
    <input type="submit" />
}

And in your HttpPost action method, We will have a paramer of type ShoppingCartViewModel. When the form is submitted, MVC Model binder will map the posted form values to an object of ShoppingCartViewModel.

[HttpPost]
public ActionResult Index(ShoppingCartViewModel model)
{
    foreach (var item in model.CartItems)
    {
        var productId = item.Id;
        // to do  : Use productId and do something
    }
    return RedirectToAction("OrderSucessful");
}

You can iterate through the CartItems collection and get the Id of the Products and do whatever you want.

enter image description here

If you wan't to allow the user to edit the items (using a check box) in this page, Take a look at this answer. It is basically same, but you add a boolean property to Product class and use that for rendering a checkbox.

Community
  • 1
  • 1
Shyju
  • 214,206
  • 104
  • 411
  • 497