ASP.NET集合模型绑定嵌套表单问题

发布于 2024-08-21 20:02:07 字数 2689 浏览 6 评论 0原文

我有一个绑定到对象购物车的部分视图。 Cart 有一个 CartLines 集合。我的看法如下:

        <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>

有两点需要注意。第一个是我使用每行一个表单来删除项目。

第二个是我试图允许用户更改行项目的数量,然后单击更新按钮将所有更改传递给控制器​​操作:

        // 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 });
    }

请注意,我正在使用字典,因为我只关心产品和数量。我真的不喜欢这样的事实:在调用 cart.UpdateItem 之前我必须再次检索产品,但我不知道如何将产品从模型传递到我的操作而不是 id。

然而,主要的问题是,我相当愚蠢地将整个购物车包装在一个表单中,以便我可以发回值,然后花了一个小时思考为什么事情在 IE 中无法正常工作 - 哎呀!嵌套表单

所以我被困在如何解决这个问题上。我希望能够单独删除项目,但允许用户更改项目数量,然后将所有更改立即传递给控制器​​。我无法使用链接进行删除操作,因为我需要使用 javascript 来强制发布帖子,并且所有内容都必须在不启用 javascript 的情况下正常工作。

[更新]

更好的解决方案是允许更新我的自定义模型绑定器吗?这样我就可以在视图中进行更改并将购物车对象发布回控制器 - 尽管我不确定这对于子集合(Cart.CartItems)是否可行。 我看过像亚马逊这样的网站,看起来他们将整个购物车包装在一个表单中,并且当禁用 JavaScript 时,全局更新按钮和单独的删除项目按钮都会发回相同的操作。 如有任何帮助,我们将不胜感激。

谢谢, 本

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 is 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

丑疤怪 2024-08-28 20:02:07

这里只有一种方法,那就是丑陋的方法。一切事物都有一种形式。
然后在操作中,您必须检查按下了哪个按钮(您在请求中获取按钮的名称)。

由于 firefox 和 ie 的差异,它变得更加难看。如果您按下了按钮,ie 或 firefox(不记得是哪一个)不仅会发送按下按钮的名称,还会发送按下按钮的位置。

如果您的解决方案可以依赖支持 JS 的浏览器,您就有更多选择。但那是另一个故事了。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文