Knockout使用映射插件刷新viewModel

时间:2013-01-03 23:41:53

标签: javascript jquery json knockout.js mapping

我正在尝试使用knockout和映射插件刷新一个小部件。到目前为止,这是我的代码:

var AppViewModel = function (data, total, qty) {
    var self = this;
    self.Products = ko.mapping.fromJS(data, {}, this);
    self.CartTotals = ko.observable(total);
    self.TotalQty = ko.observable(qty);
};

var func = function(u) {
    return $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", data: "{}", dataType: "json", url: u });
},
getQtyTotal = function(b) {
    var a = 0;
    $.each(b.Table.Rows, function(c) {
        a += parseInt(b.Table.Rows[c].Quantity) || 0;
    });
    return a;
};

$.when(func("/store/MiniCart.aspx/GetShoppingCartInfo"), func("/store/MiniCart.aspx/GetCartTotal")).done(function (jsonA, jsonB) {
    var ds = $.parseJSON(jsonA[0].d), ds2 = $.parseJSON(jsonB[0].d), qtyTotal = getQtyTotal(ds);
    ko.applyBindings(new AppViewModel(ds, ds2, qtyTotal));
});

<div class="cartDropDownProductItemWrapper" data-bind="foreach: Products.Table.Rows">
    <div class="cartDropDownProductItem">
        <div class="cartDropDownProductImg">
            <img id="cart_details_rpt_prod_image_0" style="height: 71px; width: 55px;" data-bind="attr: { src: ProductImageURL }">
        </div>

        <div class="cartDropDownProductDesc">
            <h6><a data-bind="text: ModelName, attr: { href: ProductLink }"></a></h6>
            <div class="cartDropDownProductDescInner">
            <div class="cartDropDownColor"> COLOR 
                <strong><span data-bind="text:ColorName"></span></strong>
            </div>
            <div class="cartDropDownSize"> SIZE
                <strong><span data-bind="text: SizeName"></span></strong>
            </div>
            <div class="cartDropDownSize"> QTY 
                <strong><span data-bind="text: Quantity"></span></strong>
            </div>
            <div class="cartDropDownPrice"> PRICE 
                <strong><span data-bind="text: UnitCost().toFixed(2)"></span></strong>
            </div>
            <div class="cartDropDownRemove">
                <a href="javascript:void(0);" class="remove" onclick="removeItem('v3BuhngpE4c=')">
                    <img src="/images/layout/icons/remove.gif" alt="Remove Item">
                </a>
            </div>
        </div>
    </div>
    <div class="clear"></div>
</div>


<!-- end fo reach -->
<div class="clear"></div>
<div class="cartDropDownButtons clearfix">
    <ul class="clearfix">
        <li class="countItems"><span data-bind="text: TotalQty"></span> Items</li>
        <li class="subTotal" id="subTotal">SUBTOTAL: $<span data-bind="text: CartTotals().toFixed(2)"></span></li>
    </ul>
</div>

它渲染得很好,但是当我尝试重新绑定jQuery click事件并调用:

   ko.applyBindings(new AppViewModel(ds, ds2, qtyTotal));

它复制了数据。

2 个答案:

答案 0 :(得分:2)

如果你开始创建一个空的viewModel ...它不会通过它的构造函数获取参数,如下所示:

function ViewModel()
{
    var self = this;
}
var viewModel = new ViewModel();

...然后您可以通过名称引用它来使用ko.mapping加载数据,如下所示:

ko.mapping.fromJS({ "PropertyName": plainJsObject }, {}, viewModel);

这样做是在plainJsObject上运行 ko.mapping magic ,并将结果填充到viewModel对象的属性(在本例中,称为PropertyName)。

您特别关注的部分是:

如果要使用服务器中的新数据刷新viewModel.PropertyName中的数据...您只需调用完全相同的方法,并在viewModel上更新相同的属性。只需在plainJsObject中使用新值再次调用同样的东西:

ko.mapping.fromJS({ "PropertyName": plainJsObject }, {}, viewModel);

由于您(我假设)已经在代码中的某个位置执行了ko.applyBindings(),因此上面的这一行会立即更新您的视图。

答案 1 :(得分:0)

您应该只需要执行一次绑定,所以只需将其保留在任何事件驱动的函数调用之外。

 ko.applyBindings(new AppViewModel(ds, ds2, qtyTotal));

我认为你在上面的例子中使你的代码复杂化了。我将返回一组Product对象,其中包含描述,单价,数量等属性,然后计算总数,使用ko计算变量,如果用户试图增加/减少数量,它将自动更新。

function Product(item) {
    var self = this;
    self.description = ko.observable(item.description);
    self.quantity = ko.observable(item.quantity);
    self.unitPrice = ko.observable(item.unitPrice);
    self.total =  ko.computed(function() {
        return self.quantity() * self.unitPrice();
    });
}

function AppViewModel() {
    var self = this;
    self.products = ko.observableArray([]);
    self.overvallTotal =  ko.computed(function() {
        var total = 0;
        for (var i = 0; i < self.products().length; i++) {
            total += self.products()[i].total;
        }
        return total;
    });        
    self.removeProduct = function(item) { self.products.remove(item) };

    // Load initial state from server, convert it to Product instances
    $.getJSON("/store/MiniCart.aspx/GetShoppingCartInfo", function(allData) {
        var mappedProducts = $.map(allData, function(item) { return new Product(item) });
        self.products(mappedProducts);
    });    
}

ko.applyBindings(new AppViewModel());

您必须调整服务器端json结果才能使用此功能。