Knockout - 更新observableArray of Models

时间:2013-06-12 13:33:18

标签: javascript knockout-2.0

我正试图解决淘汰问题。我想要做的是拥有一个根模型,包含另一个模型的observableArray。该模型还包含一个最后一个模型的observableArray(称为“Result”)。 根据用户交互,可以完全更改第一个observableArray(重置阵列并添加其他模型)。

向用户呈现一个列表,他能够使用文本字段过滤结果(我使用的是计算过滤器)。

我面临的问题是,即使我重置了observableArray,似乎引用仍然保留在嵌套模型中,并且knockout继续在这些模型上触发事件,这导致越来越多的Javascript调用用户更改列表。

我写了一个小jsfiddle来表明我的意思:http://jsfiddle.net/PNzM5/ 这是javascript代码:

ko.observableArray.fn.pushAll = function (valuesToPush) {
    var underlyingArray = this();
    this.valueWillMutate();
    ko.utils.arrayPushAll(underlyingArray, valuesToPush);
    this.valueHasMutated();
    return this;
};

function Result(value) {
    this.value = ko.observable(value);
}

function NestedItem(name, currentValue) {
    var _this = this;
    this.currentValue = currentValue;
    this.name = ko.observable(name);
    this.totalResults = ko.observableArray([]);
    this.filteredResults = ko.computed(function () {
        console.log('get called by ' + _this.name());
        return ko.utils.arrayFilter(_this.totalResults(), function (result) {
            return result.value().toLowerCase().indexOf(_this.currentValue()) != -1;
        });
    });
}

function Model() {
    var _this = this;
    this.nestedItemList = ko.observableArray([]);
    this.currentValue = ko.observable("");

    this.createFirstList = function () {
        this.nestedItemList([]);
        _this.createItem("sublist 1", [new Result("value 1"), new Result("value 2"), new Result("value 3")]);
        _this.createItem("sublist 2", [new Result("value 4"), new Result("value 5"), new Result("value 6")]);
    }

    this.createSecondList = function () {
        this.nestedItemList([]);
        _this.createItem("sublist 3", [new Result("value 1"), new Result("value 2"), new Result("value 3")]);
        _this.createItem("sublist 4", [new Result("value 4"), new Result("value 5"), new Result("value 6")]);
    }

    this.createItem = function (name, values) {
        var item = new NestedItem(name, _this.currentValue);
        item.totalResults.pushAll(values);
        this.nestedItemList.push(item);
    }
}

和相关的HTML:

<input data-bind="value:currentValue,valueUpdate: 'keyup'" type="text" placeholder="Type to filter"/>
<ul data-bind="foreach: nestedItemList">
    <li class="sublist" data-bind="text: name"></li>
    <!-- ko foreach: filteredResults -->
    <li class="result" data-bind="text: value"></li>
    <!-- /ko -->
</ul>
<button data-bind="event: {click: createFirstList}">First list</button>
<button data-bind="event: {click: createSecondList}">Second list</button>

我将对计算机的调用记录到控制台。如果单击“第一个列表”并尝试过滤结果,您将看到对于您键入的每个字符,将为每个列表调用计算(这很好)。然后,如果您单击“第二个列表”并尝试过滤agin,您将看到计算将被调用4次。每次点击一个按钮,你还有2个电话。

(我的真实模型要复杂得多。例如,结果包含更多属性)

我得到的真实模型是IE8告诉我脚本正在减慢IE。我怀疑这就是原因。即使不是,我想知道为什么我会得到这种行为。也许这更像是一个Javascript问题而不是Knockout问题?或者我可能做错了吗?

1 个答案:

答案 0 :(得分:0)

好的,我找到了解决方案。 在“NestedItem”中,我创建了一个重置​​函数,将结果设置为空数组:

this.reset = function() {
    _this.totalResults([]);
}

我还在根模型中创建了一个重置​​函数,每次创建一个新列表时都会调用它:

this.reset = function() {
    ko.utils.arrayForEach(_this.nestedItemList(), function(list) {
        list.reset();
    });
    this.nestedItemList([]);
}

所以,模型现在是:

ko.observableArray.fn.pushAll = function(valuesToPush) {
    var underlyingArray = this();
    this.valueWillMutate();
    ko.utils.arrayPushAll(underlyingArray, valuesToPush);
    this.valueHasMutated();
    return this;
};

function Result(value) {
    this.value = ko.observable(value);
}

function NestedItem(name, currentValue) {
    var _this = this;
    this.currentValue = currentValue;
    this.name = ko.observable(name);
    this.totalResults = ko.observableArray([]);
    this.filteredResults = ko.computed(function() {
        console.log('get called by ' + _this.name());
        return ko.utils.arrayFilter(_this.totalResults(), function(result) {
            return result.value().toLowerCase().indexOf(_this.currentValue()) != -1 ;
        });
    });
    this.reset = function() {
        _this.totalResults([]);
    }
}

function Model() {
    var _this = this;
    this.nestedItemList = ko.observableArray([]);
    this.currentValue = ko.observable("");

    this.createFirstList = function() {
        _this.reset();
        _this.createItem("sublist 1 title", [new Result("value 1"), new Result("value 2"), new Result("value 3")]);
        _this.createItem("sublist 2 title", [new Result("value 4"), new Result("value 5"), new Result("value 6")]);
    }

    this.createSecondList = function() {
        _this.reset();
        _this.createItem("sublist 3 title", [new Result("value 1"), new Result("value 2"), new Result("value 3")]);
        _this.createItem("sublist 4 title", [new Result("value 4"), new Result("value 5"), new Result("value 6")]);
    }

    this.reset = function() {
        ko.utils.arrayForEach(_this.nestedItemList(), function(list) {
            list.reset();
        });
        this.nestedItemList([]);
    }

    this.createItem = function(name, values) {
        var item = new NestedItem(name, _this.currentValue);
        item.totalResults.pushAll(values);
        this.nestedItemList.push(item);        
    }
}

我还减少了我的真实“结果”模型中的可观察数量(我有很多可观察对象,其中一些不需要是可观察的。简单的属性就足够了。我不再获得IE错误对话框了。 但是,我认为我的解决方案有点笨拙。如果有人有更好的解决方案,我会很高兴看到它。 :)

编辑:我忘记了jsfiddle:http://jsfiddle.net/PNzM5/2/