【问题标题】:Tracking changes - observable element in observableArray跟踪更改 - observableArray 中的可观察元素
【发布时间】:2013-05-02 18:14:01
【问题描述】:

我需要使用 Javascript 和 Knockout.js 在 Web 应用程序中编辑整数数组。该数组将绑定到文本框,并且每当更改任何文本框的值时,都会更新该数组。当它更新时,计算元素的总和。

这是我的第一次尝试:http://jsfiddle.net/ZLs2A/0/。它不起作用(为任何元素键入新值时,总和值不会更新)。这时候我才意识到 observableArray 只会在插入或删除项目后触发 sum 函数。

<h4>Numbers</h4>
<button data-bind="click: add">Add</button>
<ul data-bind="foreach: numbers">
    <li>
        <input data-bind="value: $data"></input>
    </li>
</ul>
<span data-bind="text: sum"></span>

function MyViewModel() {
    var self = this;

    self.numbers = ko.observableArray([
        1,
        2,
        3
    ]);

    self.sum = ko.computed(function() {
        var items = self.numbers();
        var total = 0;
        for (var i = 0; i < items.length; i++) {
            total += parseInt(items[i]);
        }
        return total;
    });

    self.add = function() {
        var lastIndex = self.numbers().length - 1;
        var lastValue = self.numbers()[lastIndex];
        self.numbers.push(lastValue + 1);
    }
}

ko.applyBindings(new MyViewModel());

我的下一个尝试是让 numbers 数组中的每个元素都成为 observable (http://jsfiddle.net/ZLs2A/1/)。它再次不起作用。

self.numbers = ko.observableArray([
    ko.observable(1),
    ko.observable(2),
    ko.observable(3)
]);

我最后一次尝试是创建一个新类 (ArrayItem) 来将元素的值保存在可观察属性中。这次成功了! (http://jsfiddle.net/ZLs2A/3/)

<h4>Numbers</h4>
<button data-bind="click: add">Add</button>
<ul data-bind="foreach: numbers">
    <li>
        <input data-bind="value: value"></input>
    </li>
</ul>
<span data-bind="text: sum"></span>

function MyViewModel() {
    var self = this;

    self.numbers = ko.observableArray([
        new ArrayItem(1),
        new ArrayItem(2),
        new ArrayItem(3)
    ]);

    self.sum = ko.computed(function() {
        var items = self.numbers();
        var total = 0;
        for (var i = 0; i < items.length; i++) {
            total += parseInt(items[i].value());
        }
        return total;
    });

    self.add = function() {
        var lastIndex = self.numbers().length - 1;
        var lastItem = self.numbers()[lastIndex];
        var newValue = parseInt(lastItem.value()) + 1;
        self.numbers.push(new ArrayItem(newValue));
    }
}

function ArrayItem(value){
    var self = this;
    self.value = ko.observable(value);
}

ko.applyBindings(new MyViewModel());

但是,我不想创建这个新类 ArrayItem。 有什么办法可以摆脱它,使示例工作只具有可观察元素的 observableArray(就像我的第二次尝试)?

【问题讨论】:

  • KO 的作者回答了this (possible duplicate?) question,基本上与您使用ArrayItem 构造函数的最终版本类似(他只是内联了该函数)。答案是一年前的,所以在此期间可能发生了一些变化......如果没有,那么您似乎已经回答了自己的问题。
  • 可能值得一提的是 Breeze.js 与 Knockout.js 的集成,其中添加了更改跟踪。 breezejs.com

标签: knockout.js


【解决方案1】:

Knockout 不会跟踪值,但作为一种解决方法,您可以使用事件按键或自己更改和更新值。见小提琴:http://jsfiddle.net/tkirda/ZLs2A/4/

function MyViewModel() {
    var self = this;

    self.numbers = ko.observableArray([
        1,
        2,
        3
    ]);

    self.onChange = function(val, e){
        var el = e.srcElement;
        var newVal = parseInt(el.value);
        var index = parseInt(el.getAttribute('data-index'));
        self.numbers()[index] = newVal;
        self.updateSum();
    }

    self.sum = ko.observable(0);

    self.updateSum = function() {
        var items = self.numbers();
        var total = 0;
        for (var i = 0; i < items.length; i++) {
            total += parseInt(items[i]);
        }
        self.sum(total);
    };

    self.updateSum();

    self.add = function() {
        var lastIndex = self.numbers().length - 1;
        var lastValue = self.numbers()[lastIndex];
        self.numbers.push(lastValue + 1);
    }
}

ko.applyBindings(new MyViewModel());

【讨论】:

  • 虽然这似乎适用于 IE11,但 jsfiddle 示例中的总和不会随着 Firefox 45.0.1 中文本字段中值的更改而更新
猜你喜欢
  • 1970-01-01
  • 2015-11-30
  • 2013-08-26
  • 1970-01-01
  • 2017-12-03
  • 1970-01-01
  • 1970-01-01
  • 2018-11-26
  • 1970-01-01
相关资源
最近更新 更多