2012-07-02 9 views
37

Я хотел бы знать, как создать вычисляемый наблюдаемый массив.Как создать вычисляемый наблюдаемый массив в Knockout

На мой взгляд, у меня есть 2 наблюдаемых массива, и я хотел бы иметь вычисленный наблюдаемый массив, который просто объединяет оба массива.

function ViewModel() { 
    var self = this; 
    self.listA= ko.observableArray([]); 
    self.listB = ko.observableArray([]); 
    self.masterList= //combine both list A and B 

ответ

33

Это объединит два массива и вернет объединенный список. Тем не менее, это не вычисленный наблюдаемый массив (не знаю, возможно ли это вообще), а регулярный вычисленный наблюдаемый.

self.masterList = ko.computed(function() { 
    return this.listA().concat(this.listB()); 
}, this); 
+18

Я считаю, этот ответ испорчен для большинства случаев использования: значение вычисленного наблюдаемого является регулярным массивом, а не наблюдаемым массивом (примерно указанным в ответе). Следовательно, обновление 'listA' или' listB' полностью заменит сам массив, а не обновит его содержимое (чего мы хотим в 99% случаев). ** Это означает, что вы не должны привязывать представления к этому наблюдаемому. ** По сути, этот код так же полезен, как и его невычислимый вариант. См. Другие ответы для разных подходов. – tne

+0

В этом случае это не сработает, но плагин для нокаута [нокаут-проекции] (https://github.com/stevesanderson/knockout-projections) реализует гораздо более эффективные вычислимые наблюдаемые массивы с использованием новых [подписки на изменение массива] (http://blog.stevensanderson.com/2013/10/08/knockout-3-0-release-candidate-available/). Этот плагин может быть расширен для поддержки эффективной операции concat. – Singularity

7

Наблюдаемый массив является наблюдаемым только с несколькими свойствами. Следовательно, вычисляемая наблюдаемая, которая возвращает массив в закрытии, будет рассматриваться как массив.

+3

Ну, вроде. Я просто протестировал его, и кажется, что, если он не объявлен как наблюдаемый массив, методы, такие как shift и pop, не вырвались для вас. – Eirinn

9

Я знаю, что это старый вопрос, но я думал, что я бросаю мой ответ там:

var u = ko.utils.unwrapObservable; 

ko.observableArray.fn.filter = function (predicate) { 
    var target = this; 

    var computed = ko.computed(function() { 
     return ko.utils.arrayFilter(target(), predicate); 
    }); 

    var observableArray = new ko.observableArray(u(computed)); 

    computed.subscribe(function (newValue) { observableArray(newValue); }); 

    return observableArray; 
}; 
10
self.masterList = ko.observableArray(); 
ko.computed(function() { 
    self.masterList(self.listA().concat(self.listB())); 
}); 

Подобный ответ Джо Flateau в духе, но мне нравится думать, этот метод проще ,

+0

Вот как я собирался это сделать, но разве это не по-прежнему страдает от вопроса как принятого ответа; что любое изменение приведет к тому, что любое представление, связанное с 'masterList', будет полностью перерисовано? –

+0

@AdamLewis: Да, это действительно перестраивает весь массив, и в зависимости от механизма просмотра он может или не может повторно отобразить весь подграф DOM для любых представлений, связанных с ним (необязательно, однако, может просто сделать diff и применить Это). Обратите внимание, что это может быть лучшим решением, чтобы избежать многих обновлений. Это не проблема, которую я изложил в отношении ответа, о котором вы упоминаете, когда, если механизм представления захватывает свойство массива сам (в отличие от пути к нему), он никогда не обнаружит, что вы поменяли массив (поскольку он не наблюдается) и таким образом никогда не будет обновлять * вообще *. – tne

+0

@tne Я использую этот ответ на данный момент, но он кажется очень медленным ... может быть, я делаю что-то еще неправильно. однако, является ли это решение нарушением намеченной цели KO?есть ли еще один способ решить проблему необходимости вычислимого наблюдаемого массива? просто интересно, правильно ли это использовать в моей (или любой) ситуации. – Nate

2

Я не уверен, что это самый эффективный вариант - но он довольно прост и работает для меня. В ko.computed возвращает наблюдаемый массив, как показано ниже:

self.computedArrayValue = ko.computed(function() { 
    var all = ko.observableArray([]); 
    .... 
    return all(); 
}); 

Рабочий пример кода: Html:

<div data-bind="foreach: days"> 
    <button class="btn btn-default btn-lg day" data-bind="text: $data, click: $root.dayPressed"></button>   
</div> 

функция Javascript на модели представления:

self.days = ko.computed(function() { 
    var all = ko.observableArray([]); 
    var month = self.selectedMonth(); //observable 
    var year = self.selectedYear();  //observable 
    for (var i = 1; i < 29; i++) { 
     all.push(i); 
    } 
    if (month == "Feb" && year % 4 == 0) { 
     all.push(29); 
    } else if (["Jan","Mar","May","Jul","Aug","Oct","Dec"].find((p) => p == month)) { 
     [29,30,31].forEach((i) => all.push(i)); 
    } else if (month != "Feb") { 
     [29,30].forEach((i) => all.push(i));     
    } 
    return all(); 
});