开发者

ASP.NET Collection Model Binding Nested Form Problem

开发者 https://www.devze.com 2022-12-20 18:27 出处:网络
I have a partial view that is bound to an object Cart. Cart has a collection of CartLines. My view is below:

I have a partial view that is bound to an object Cart. Cart has a collection of CartLines. My view is below:

        <tbody>
        <% foreach (var line in Model.Lines) { %>
        <tr>
            <td align="center"><%=Html.CatalogImage(line.Product.DefaultImage, 80) %></td>
            <td align="left">
                <%=Html.ActionLink(line.Product.Name, "Product", "Catalog",  
                    new { productId = line.Product.Id }, new { title = "View " + line.Product.Name })%>
            </td>
            <td align="right"><%= line.Product.Price.ToString("c")%></td>
            <td align="center">
                <%=Html.Hidden("lines[" + i + "].key", line.Product.Id) %>
                <%=Html.TextBox("lines[" + i + "].value", line.Quantity, new { @class = "quantity" })%>
            </td>
            <td align="right"><%= (line.LineTotal).ToString("c")%></td>
            <td>
                <%using (Ajax.BeginForm("RemoveFromCart", "Cart", 
                      new {ProductId = line.Product.Id, returnUrl = ViewData["returnUrl"]}, 
                      new AjaxOptions { UpdateTargetId="cart", LoadingElementId="loading" }))
                  {%>                           
                        <input type="image" src="<%=AppHelper.ImageUrl("delete.gif")%>" value="Remove item"  />
                <%} %>
            </td>
        </tr>
        <% i++; } %>
    </tbody>

There are two things to note. The first i开发者_Python百科s that I am using a form per line for removing items.

The second is that I had attempted to allow users to change the quantity of line items and then click an update button to pass all the changes to the controller action:

        // POST: /Cart/Update
    [HttpPost]
    public ActionResult Update(Cart cart, IDictionary<int,int> lines, string returnUrl)
    {
        foreach (var line in lines) {
            Product p = _catalogService.GetProduct(line.Key);
            cart.UpdateItem(p, line.Value);
        }

        if (Request.IsAjaxRequest())
            return PartialView("Cart", cart);
        else
            return RedirectToAction("Index", new { returnUrl });
    }

Note that I am using a dictionary since I am only concerned about the product and quantity. I don't really like the fact that I am having to retrieve the product again before calling cart.UpdateItem but I couldn't figure out how to pass the Product from the model to my action instead of the id.

The main problem however, is rather stupidly I wrapped the entire cart in a form so that I could post back the values and then spent a good hour wondering why things were not working correctly in IE - doh! nested forms

So I am stuck on how to get round this. I want the ability to remove items individually but allow a user to change item quantities and then pass all changes at once to the controller. I can't use links for my remove action as I would need to use javascript to force a post and everything must work without javascript enabled.

[Update]

Would a better solution be to allow updates on my custom model binder? This way I could make changes inside my view and post the cart object back to the controller - although I'm not sure whether this is possible with child collections (Cart.CartItems). I've had a look on sites like Amazon and it would appear they wrap the entire cart in a form and both global update buttons and indidivual remove item buttons post back to the same action when javascript is disabled. Any help would be appreciated.

Thanks, Ben


There is only one way here and thats the ugly way. Have 1 form around everything. Then in the action you have to check which button was pressed (you get the name of the button in the request).

It gets even more ugly with differences in firefox and ie. If you have a button pressed ie or firefox (Dont remember which one) not only sends the name of the pressed button, but also the location where the button was pressed.

You have more options if your solution can rely on JS enabled browsers. But thats another story.

0

精彩评论

暂无评论...
验证码 换一张
取 消