Knockout - 将值写入ko.computed

时间:2014-06-05 14:04:04

标签: javascript knockout.js knockout-2.0

我在Knockout中构建了一个非常数据/号码的应用程序。我目前收到错误:

  

未捕获错误:除非您,否则无法将值写入ko.computed   指定'write'选项。如果您想读取当前值,请不要   传递任何参数。

当我的自定义bindingHandler(将数字格式化为'large'形式,即123,345,678,987)尝试写回显示计算函数值的原始输入时,就会发生这种情况。

输入元素中显示的值:

self.value = ko.computed(function(){
    return self.chosenAge().population; // 'fetched' from an array.
});

绑定处理程序:

ko.bindingHandlers.largeNumber = {
    init: function(element, valueAccessor) {
        numberInit(element);
        var value = valueAccessor();
        var interceptor = ko.computed({
            read: function() {
                // inject number formatting
                return numeral(ko.unwrap(value)).format('0,0');
            },
            write: function(newValue) {
                // remove formatting when writing a new value
                value(numeral().unformat(newValue));
            }
        });
        // display new value in target element
        if(element.tagName.toLowerCase() == 'input' ) {
            ko.applyBindingsToNode(element, {
                value: interceptor
            });
        }
        else {
            ko.applyBindingsToNode(element, {
                text: interceptor
            }); 
        }
    }
};

2 个答案:

答案 0 :(得分:1)

您需要在ko.computed函数中指定'write'选项。请参阅documentation on computed observables。绑定处理程序与您的值无法更新无关。你的计算机应该是这样的:

self.value = ko.computed(function(){
    read: function () {
        return self.chosenAge().population; // 'fetched' from an array.
    },
    write: function (value) {
        //update your self.chosenAge().population value here
    },
    owner: self
});

希望这有帮助。

答案 1 :(得分:0)

就个人而言,我会在extender中捕获格式的实现。

使用computed格式化程序定义包含数据可观察数​​据的扩展名:

ko.extenders.largeNumber = function (target, option) {

  var formatter = ko.computed( {
    read: function(){
    var formatted = target().toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    return formatted;
  },
    write: function(nv){
        var numeric = nv.replace(/,/g,""); 
        target(numeric);

        console.log("View model now contains " + target())
  }
 })
 return formatter;
};

然后创建一个使用扩展名的observable :(我把它包装在构造函数中)

function createExtendedObs(initialValue){
    return ko.observable(initialValue).extend({
    largeNumber: {
        viewModel: self
    }
 });

另外,我将使我的observable成为数据对象中代表population

chosenAge属性
{
  name: "Bronze",
  population: createExtendedObs(10000)
}

这不是必需的。如果您希望将填充存储在另一个可观察对象中,我会设置扩展程序以通过options参数访问viewModel。因此,您可以通过这种方式访问​​其他可观察对象。如果要计算“其他”可观察量,那么您需要指定write函数(,如另一个答案所示),这是您遇到的问题的根源。另一种选择是subscribechosenAge,并在订阅中设置“其他”人口可观察。

直接使用data属性,我可以按如下方式绑定它,

<div data-bind='with: chosenAge'>  
  <input data-bind='value: population'></input>
</div>

查看my fiddle完整设置。


修改

刚刚审核了有关想要输入“格式化”值的评论。每次计算机接收到新值时,都会格式化该字段。默认情况下,这将是焦点丢失。如果要在提供输入时修改它,则需要提供valueUpdate绑定参数。 由于字段被动态操作,这将导致插入符定位问题。您需要相应地管理插入位置。

<input data-bind='value: population, valueUpdate: "afterkeydown"'></input>