Подтвердить что ты не робот

Поддержка ko.observableArray для ассоциативных массивов

Есть ли лучший способ (встроенный?) для смешивания наблюдаемых массивов и ассоциативных массивов?

viewModel = {
    a: ko.observableArray(),
    a_assoc: {},
    add_item: function(i) {
        if (typeof this.a_assoc[i] == 'undefined') {
            this.a.push(i);
            this.a_assoc[i]=1;
        }
    }
}

viewModel.add_item('bla');
4b9b3361

Ответ 1

Как правило, вы делаете что-то подобное в Knockout:

var viewModel = {
    a: ko.observableArray(["a","b","c","d"]),
    add_item: function() {
       this.a.push("new" + this.a().length);   
    }
};

viewModel.a_assoc = ko.dependentObservable(function() {
    var result = {};
    ko.utils.arrayForEach(this.a(), function(item) {
       result[item] = 1;
    });
    return result;
}, viewModel);

Итак, у вас есть independentObservable, который сопоставляет ваш массив с объектом. Обратите внимание, что каждый раз, когда исходный массив обновляется, объект перестраивается. Таким образом, он менее эффективен, чем метод в вашем сообщении, но если ваш объект существенно большой, сомнительно, что это вызовет проблему с производительностью.

Пример здесь: http://jsfiddle.net/rniemeyer/PgceN/

Ответ 2

Я думаю, что лучше использовать ассоциативный массив под капотом для производительности. Вы также (как вы указали) должны использовать наблюдаемый массив для отслеживания изменений (потому что это работает нокаут).

Если вы ищете ассоциативный массив с "нокаутом", вам, вероятно, нужен способ отслеживания изменений в элементе (и, таким образом, влиять на цепи зависимостей).

http://jsfiddle.net/rz41afLq/2/

Вот то, что я придумал, соответствовало моим потребностям. В основном вы храните пару значений ключа в observableArray и используете стандартный ассоциативный массив для хранения копии для поиска.

// VIEW MODEL
var viewModel = {

    // we have to use observable array to track changes
    items: ko.observableArray([]),

    // also use associative array for performance
    _assoc: {},

    update_item: function(key, value) {

        // use a true assoc array for performance
        // _assoc[key] = ko.observable(value)
        if (viewModel._assoc[key])
        {
            // update observable (overwriting existing item)
            viewModel._assoc[key].value(value);
        }
        else { 
            // Important: See how we wrap value with an observable to detect changes
            this.items.push(viewModel._assoc[key] = { key: key, value: ko.observable(value) });
        }
    }
};

Итак, вы сохраняете своих собак следующим образом:

update_item('dogs', ['kim', 'abbey', 'goldie', 'rover']);
update_item('dogs', ko.observableArray(['kim', 'abbey', 'goldie', 'rover']));

(Вторая требуется только в том случае, если вы планируете вызывать pop() или push() в списке собак и хотите обновить пользовательский интерфейс. Вы можете, конечно, позвонить update_item, чтобы полностью обновить элемент в любое время и в этом случае его не нужно наблюдать)

Чтобы найти значение, вы динамически создаете вычисленное для его получения:

var dogs = getValue('dogs');

Затем, как только значение, индексированное как "собаки" в ассоциативном массиве, изменится, тогда наблюдаемый dogs() будет обновляться (и может быть привязан). Этот наблюдаемый dogs может быть связан с UI, конечно,

var getValue = function(key) { return ko.pureComputed(function() 
{
    // reevaluate when item is added or removed to list
    // not necessary if the value itself changes
    viewModel.items();                                                      

    var item = viewModel._assoc[key];
    return (item == null) ? null : item.value();

}, viewModel);