【问题标题】:knockout update observable collection from property on viewmodel从视图模型的属性中剔除更新可观察的集合
【发布时间】:2014-03-12 23:18:36
【问题描述】:

我正在使用敲除为一个项目创建一个基本的 AJAX 购物车,并且当视图模型上的属性更新时,视图模型内的可观察集合中包含的单个产品的成本需要更新。我已经尝试了好几个小时的各种解决方案,我希望有人能指出我正确的方向。我已经包含了一个 jsfiddle。

http://jsfiddle.net/g8BLj/3/

var product = function (title, operationName, description, parent) {
  this.title = title;
  this.operationName = operationName;
  this.description = description;
  this.cost = 9;
  this.count = ko.observable(parent.recordCount);
  this.subtotal = ko.computed(function () {
    return this.count * this.cost;
  }).bind(this);
};

order = function () {
 var listName = ko.observable("not defined"),
     listId = ko.observable("not defined"),
     recordCount = ko.observable("not defined"),
     products = [
     new product('Product1', 'EMAIL_VER_DELIVERABLE', 'Description.', this),
     new product('Product2', 'EMAIL_BASIC_NO_SUPRESSION_W_VERIFICATION', 'Description.', this),
     new product('Product3', 'PHONE_PREM', 'Description.', this)],
     total = function () {
        var total = 0;
        $.each(this.products(), function () {
            total += this.subtotal();
        });
        return total;
     };

 // anything in the return block is considered public, anything above is private
 return {
    listName: listName,
    listId: listId,
    recordCount: recordCount,
    products: products,
    total: total
 };
}();

ko.applyBindings(order);

// when this value changes the product Cost needs to be updated
order.listName('test list')
order.listId(1)
order.recordCount(100)

谢谢, 克里斯

【问题讨论】:

    标签: javascript mvvm knockout.js collections observable


    【解决方案1】:

    “this”作用域有几个问题会导致问题。

    this.subtotal = ko.computed(function () {
      return this.count * this.cost;
    }).bind(this);
    

    正确获取环境 this 范围的正确方法是将“this”作为第二个参数传递给 ko.computed。此外,count 是一个可观察的,您需要对其进行评估。

    this.subtotal = ko.computed(function () {
      return this.count() * this.cost;
    }, this);
    

    products 变量将“this”传递给 product 的构造函数。此时的环境 this 是窗口,就像您使用匿名函数/显示模块模式一样。

    所以当

     this.count = ko.observable(parent.recordCount);
    

    评估,父级是窗口,所以recordCount == undefined。

    如果您想继续使用显示模块模式,您需要 tweek 订单函数来声明您的返回对象(“obj”),然后创建产品。

    您还应该将总属性声明为 ko.computed。我使用了 map/reduce 而不是 $.each,但这是个人喜好。

    完成后,它揭示了产品类的计数属性的进一步问题。 parent.recordCount 是一个 observable,因此您正在创建一个 observable,其值是 observable,而不是 observable 的值。只需将 observable 分配给 count 属性即可。


    var product = function (title, operationName, description, parent) {
        this.title = title;
        this.operationName = operationName;
        this.description = description;
        this.cost = 9;
        this.count = parent.recordCount;
        this.subtotal = ko.computed(function () {
            return this.count() * this.cost;
        }, this);
    };
    
    order = function () {
        var
        listName = ko.observable("not defined"),
            listId = ko.observable("not defined"),
            recordCount = ko.observable("not defined"),
            products = [];
    
        var obj = {
            listName: listName,
            listId: listId,
            recordCount: recordCount,
            products: products
        }
    
        // now we have an object to push into the product class
        products.push(
            new product('Product1', 'EMAIL_VER_DELIVERABLE', 'Description.', obj),
            new product('Product2', 'EMAIL_BASIC_NO_SUPRESSION_W_VERIFICATION', 'Description.', obj),
            new product('Product3', 'PHONE_PREM', 'Description.', obj)
            );
    
        obj.total = ko.computed( function() {
            return this.products
                .map(function(item) { return item.subtotal(); })
                .reduce( function(runningTotal, subtotal) { return runningTotal + subtotal;
            }, 0);
        }, obj);
    
        // anything in the return block is considered public, anything above is private
        return obj;
    }();
    
    ko.applyBindings(order);
    
    // when this value changes the product Cost needs to be updated
    order.listId(1);
    order.listName('test list');
    order.recordCount(100);
    

    【讨论】:

      【解决方案2】:

      我认为,解决这个问题最重要的是使用订阅order.recordCount更改而不是将order作为参数发送给product
      你可以这样写:

      recordCount.subscribe(function (newValue) {
          ko.utils.arrayForEach(products, function (product) {
              product.count(newValue);
          })
      });
      

      另外,你应该改变product.subtotal的计算:

      this.subtotal = ko.computed(function () {
          return this.count() * this.cost;
      }, this);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-23
        • 2023-03-07
        • 2018-05-13
        • 2010-11-04
        • 2020-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多