2013-06-12 5 views
0

Я пытаюсь решить проблему с нокаутом. То, что я пытаюсь сделать, это иметь корневую модель, содержащую наблюдаемый массив другой модели. Эта модель также содержит наблюдаемый массив одной последней модели (называемой «результат»). В зависимости от взаимодействия пользователя первый наблюдаемый массив может быть полностью изменен (сброс массива и добавление других моделей).Нокаут - Обновление наблюдаемого массива моделей

Список предоставлен пользователю, и он может фильтровать результаты с помощью текстового поля (я использую вычисление для фильтрации).

Проблема, с которой я столкнулся, заключается в том, что даже если я сброшу наблюдаемый массив, кажется, что ссылки хранятся на вложенных моделях, а нокаут продолжает возбуждать события на этих моделях, что приводит к тому, что все больше и больше вызовов 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, чем проблема с нокаутом? Или, может быть, я делаю это неправильно?

ответ

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. Но все же, я думаю, что мое решение немного хаки. Если у кого-то есть лучшее решение, я был бы рад увидеть его. :)

EDIT: Я забыл jsfiddle: http://jsfiddle.net/PNzM5/2/

Смежные вопросы