【问题标题】:Knockout - Updating observableArray of Models淘汰赛 - 更新模型的 observableArray
【发布时间】:2013-06-13 16:21:59
【问题描述】:

我正在尝试解决淘汰赛的问题。我想做的是拥有一个根模型,其中包含另一个模型的 observableArray。该模型还包含最后一个模型的 observableArray(称为“结果”)。 根据用户交互,第一个 observableArray 可以完全改变(重置数组并添加其他模型)。

向用户呈现一个列表,他可以使用文本字段过滤结果(我正在使用计算过滤)。

我面临的问题是,即使我重置 observableArray,似乎仍保留对嵌套模型的引用,并且淘汰赛继续在这些模型上触发事件,这导致越来越多的 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 次。

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

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

【问题讨论】:

    标签: javascript knockout-2.0


    【解决方案1】:

    好的,我找到了解决方案。 在“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/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-13
      • 1970-01-01
      • 2013-05-17
      • 1970-01-01
      相关资源
      最近更新 更多