How to update the quantity of all items in the cart with one update button
I have the following action method, when I press the update button on my cart and post to this method I need it bind all productId and partquantity values into the respective parameters/arrays (int[] ProductId, int[] partquantity) and it does this. I am presuming when form data, that is keys and values are posted they arrive in some sort of order, likely as elements are laid out on the HTML page (top to bottom)? So I wish for the operation on each cart item to be performed using the correct partquantity entered, that is for the correct productId. I am guessing if they post and bind in strict order then partquantity[2] should be the correct quantity for ProductId[2] etc. ?
The below logic in trying to increment f by 1 for each operation on each productId in the ProductId[] array does not work. I need to get this to work because say I have 5 items added to the cart and change the quantity for 4 of them I wish to just press the one update button and it will update for all these items\lines in the cart. So method needs to catch all the posted productId and quantities and use in the correct order, so the right quantity is assigned to the right cart item which is looked up by ProductId.
public RedirectToRouteResult UpdateCart(Cart cart, int[] ProductId, int[] partquantity, string returnUrl)
{
int f = 0;
int x = partquantity.Length;
while (f <= x)
{
foreach (var pid in ProductId)
{
f++;
var cartItem = cart.Lines.FirstOrDefault(c => c.Product.ProductID == pid);
cartItem.Quantity = partquantity[f];
}
}
return RedirectToAction("Index", new { returnUrl });
}
This is the View:
<% foreach (var line in Model.Cart.Lines)
{ %>
<tr>
<td align="center"><%: Html.TextBox("partquantity", line.Quantity)%></td>
<td align="left"><%: line.Product.Name%></td>
<td align="right"><%: line.Product.ListPrice.ToString("c")%></td>
<td align="right">
<%: (line.Quantity * line.Product.ListPrice).ToString("c")%>
</td>
</tr>
<%: Html.Hidden("ProductId", line.Product.ProductID)%>
<% } %>
Custom Binder
public class CartModelBinder : IModelBinder
{
private const string cartSessionKey = "_cart";
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.Model != null)
throw new InvalidOperationException("Cannot update instances");
Cart cart = (Cart)controllerContext.HttpContext.Session[cartSessionKey];
if (cart == null)
{
cart = new Cart();
controllerContext.HttpContext.Session[cartSessionKey] = cart;
}
return c开发者_开发技巧art;
}
}
}
Your Cart object should be enough as parameter for this scenario, you can have something like this.
The general idea would be to use an index so you get your Cart object with your Lines as you passed them to the view originally but with updated Quantity values.
Your model as I understand it:
public class Cart
{
...
public List<CartItem> Lines {get; set; }
}
public class CartItem
{
public Product Product {get; set;}
public int Quantity {get; set;}
...
}
In your view:
@model Cart
...
@using(Html.BeginForm())
{
@{ int index = 0; }
@foreach(var l in Model.Lines)
{
@Html.Hidden("cart.Lines.Index", index);
@Html.Hidden("cart.Lines[" + index + "].Product.ProductID", l.Product.ProductID)
@Html.TextBox("cart.Lines[" + index + "].Quantity")
@{ index++; }
}
<input type="submit" value="Update Quantity" />
}
Your controller:
public ActionResult UpdateCart(Cart cart)
{
// you should have new values on Quantity properties of the cart.Lines items.
}
Wouldn't it be easier to have an Object - say BasketItem that has the productId and the quantity as Properties? so you would have one array/list/ienumerable to pass on to update and to bind.
Your problem would be obsolete since the connection between quantity and productid is done via the object.
精彩评论