有条件地删除Knockout.js中的根级别和嵌套的observableArrays

时间:2012-08-24 01:16:01

标签: javascript arrays knockout.js knockout-mapping-plugin

jsFiddle http://jsfiddle.net/brandondurham/g3exx/

我正在进行购物车设置并在我的模型中使用以下JSON数据:

{
    "cartItems" : [
        {
            "itemName" : "Product 1",
            "itemDesc" : "One year subscription through 14 November 2013",
            "itemType" : "subscription",
            "itemPrice" : 299,
            "itemFreebies" : false
        }, {
            "itemName" : "Product 2",
            "itemDesc" : "OpenType format",
            "itemType" : "desktop",
            "itemPrice" : 4499,
            "itemFreebies" : [{
                "freebieName" : "Product 2-a",
                "freebieDesc" : "included with your workstation license",
                "freebieOriginalPrice" : 99
            }]
        }, {
            "itemName" : "Product 3",
            "itemDesc" : "OpenType format",
            "itemType" : "desktop",
            "itemPrice" : 8999,
            "itemFreebies" : [{
                "freebieName" : "Product 3-a",
                "freebieDesc" : "included with your workstation license",
                "freebieOriginalPrice" : 99
            }]
        }, {
            "itemName" : "Product 4",
            "itemDesc" : "OpenType format",
            "itemType" : "desktop",
            "itemPrice" : 99,
            "itemFreebies" : [{
                "freebieName" : "Product 4-a",
                "freebieDesc" : "included with your workstation license",
                "freebieOriginalPrice" : 99
            }]
        }, {
            "itemName" : "Product 5",
            "itemDesc" : "",
            "itemType" : "webfont",
            "itemPrice" : 49,
            "itemFreebies" : false
        }, {
            "itemName" : "Product 6",
            "itemDesc" : "for use with Cloud.typography",
            "itemType" : "webfont",
            "itemPrice" : 99,
            "itemFreebies" : false
        }
    ]
}

购物车中某些类型的商品之间存在某种关系。例如,此JSON中的第一项是itemType“订阅”。当用户在购物车中订阅时,他们会获得一些免费的东西,具体取决于购物车中的其他内容(因此某些项目中嵌套的itemFreebies数组)。他们还被允许添加与此订阅相关的某些类型的项目(即“webfonts”)。因此,当用户从他们的购物车中删除订阅时,还必须删除所有这些免费项目和webfonts。这是我目前用来执行此操作的功能:

removeRelatives: function (itemType) {
    var siblings = CartModel.cartItems();
    switch (itemType) {
        case "subscription":
            CartModel.cartItems.remove(function(item) { return item.itemType() == "webfont" });
            $.each(CartModel.cartItems(), function(index, sib) {
                if (sib.itemFreebies) {
                    sib.itemFreebies.removeAll();
                }
            });
        break;
    }
}

此行删除与“webfont”`itemType:

匹配的所有根级项目
CartModel.cartItems.remove(function(item) { return item.itemType() == "webfont" });

第二个位循环遍历所有cartItems并搜索非{0}个非假的节点并删除它:

itemFreebies

这是第二位,我不确定。它有效,但我怀疑这不是最干净的方法。此外,我为嵌套$.each(CartModel.cartItems(), function(index, sib) { if (sib.itemFreebies) { sib.itemFreebies.removeAll(); } }); 设置的beforeRemove动画无效。移除后,它们会从屏幕上消失。

以下是HTML方面的内容:

itemFreebies

关于我的<ul id="cart-contents" data-bind="template: { name: 'cart-item-template', foreach: cartItems, beforeRemove: CartPackage.beforeRemove }"> </ul> <div id="running-totals"> <div class="totals" data-bind="visible: cartItems().length > 0"> <div><strong>Subtotal</strong></div> <div><span class="denomination">USD</span> <strong id="subtotal"><span data-bind="formatUSD: CartPackage.totalSurcharge()"></span></strong></div> </div> <div class="empty-cart">There are currently no items in your shopping cart.</div> </div> <div class="call-to-action" data-bind="visible: cartItems().length > 0"> <div class="split"> <div class="messages">&nbsp;</div> <div class="actions"> <button class="cancel">Continue Shopping</button> <button class="action">Checkout</button> </div> </div> </div> <input type="hidden" value="" data-bind="value: cartItems().length"> <script type="text/html" id="cart-item-template"> <li> <button class="delete-item">Delete</button> <ul> <li data-bind="attr: {'class': itemType}"> <div class="details"> <h5><strong data-bind="text: itemName">Product Name</strong><!-- ko if: itemType() === 'desktop' --> Desktop fonts<!-- /ko --><!-- ko if: itemType() === 'webfont' --> Webfonts<!-- /ko --></h5> <p data-bind="text: itemDesc">One year subscription through 14 November 2013</p> </div> <div class="quantity"> <!-- ko if: itemType() === "subscription" --><select data-bind='options: SubscriptionData, optionsText: "name", optionsValue: "price", value: itemPrice'></select><!-- /ko --> <!-- ko if: itemType() === "desktop" || itemType() === "webfont" --><select data-bind='options: DesktopData, optionsText: "name", optionsValue: "price", value: itemPrice'></select><!-- /ko --> </div> <div class="cost" data-bind="formatUSD: itemPrice">$ 0</div> </li> <!-- ko if: itemFreebies --> <!-- ko foreach: itemFreebies, beforeRemove: CartPackage.beforeRemove --> <li class="webfont"> <div class="details"> <h5><strong data-bind="text: freebieName">Product</strong> Webfonts</h5> <p data-bind="text: freebieDesc">Included with your workstation license</p> </div> <div class="quantity">&nbsp;</div> <div class="cost"> <span class="original-price" data-bind="formatUSD: freebieOriginalPrice">$ 49.00</span> <span class="free">FREE!</span> </div> </li> <!-- /ko --> <!-- /ko --> </ul> </li> </script> 无法正常工作的建议?更清洁的方式来实现我想要做的事情?

谢谢!如果您需要查看更多代码,请与我们联系...

1 个答案:

答案 0 :(得分:1)

对于beforeRemove动画,看起来它只是我在上面评论中列出的语法问题。

似乎从我现在能够讲述的内容开始正常运作:http://jsfiddle.net/rniemeyer/g3exx/3/

对于删除免费赠品的代码,您可以将其简化为:

$.each(CartModel.cartItems(), function(index, sib) {
    sib.itemFreebies([]);
});

对于这段关系,我认为没有一种简单的方法可以比你现在所做的更好地建模。一种想法是在根视图模型上创建计算的observable,表示任何整体概念,如hasSubscription。然后,如果该值发生变化,每个购物车项目都可以订阅hasSubscription并删除自己的免费赠品。它至少会在订阅购物车商品和其他购物车商品之间添加一些间接费用。但是,它会增加您映射项目的方式的复杂性。

如果你想要追求这样的选择,我会很乐意进一步提供帮助。