Привязать сортируемое значение индекса к нокаутному модулю представления

У меня есть структура json, которая выглядит следующим образом, где «Позиция» — это значение сортировки.

 [
  {"ID":1, "Title":"Title 1", "Position":1},
  {"ID":2, "Title":"Title 2", "Position":2},
  {"ID":5, "Title":"Title 3", "Position":3},
  {"ID":7, "Title":"Title 4", "Position":99}
];

knockout-sortable использует индекс для сортировки сортируемых элементов.

Есть ли способ привязать это сортируемое значение индекса к моему свойству Position?

Вот jsFiddle моего кода.

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


person Brad Bamford    schedule 22.06.2013    source источник


Ответы (2)


Для чего-то подобного мне нравится добавлять подписку к моему observableArray, которая выполняет один проход по массиву и правильно устанавливает «индекс».

Вот расширение, которое подойдет для вашего варианта использования:

ko.observableArray.fn.withIndex = function(prop, startIndex, lastIndex) {
    //by default use an "index" observable
    prop = prop || "index";

    //whenever the array changes, make a single pass through to update the indexes
    this.subscribe(function(newValue) {
        var item;
        for (var i = 0, j = newValue.length; i < j; i++) {
            //create the observable if it does not exist
            item = newValue[i];

            if (!item[prop]) {
                item[prop] = ko.observable();
            }

            //special logic for the last one 
            item[prop]((lastIndex && i === (j - 1)) ? lastIndex : startIndex + i);   

        }
    }, this);

    return this;
};

Вы бы использовали его как:

myObservableArray.withIndex("Position", 1, 99);

Вот ваш обновленный пример: http://jsfiddle.net/rniemeyer/HVNUr/

person RP Niemeyer    schedule 22.06.2013
comment
Это прекрасно! Он делает именно то, что должен делать, и делает это нокаутирующим способом. - person Brad Bamford; 22.06.2013
comment
Вот немного обновленный jsFiddle, который также содержит исправление проблемы isDirty. - person Brad Bamford; 24.06.2013

Я добавил идентификатор в контейнер списка, чтобы я мог «слушать» модификации dom, которые его изменяют. Я оборачиваю процесс обновления позиции в таймер, потому что событие модификации dom срабатывало слишком много раз.

var positions = ko.utils.arrayMap(viewModel.Items(), function (item) {
    return item.Position();
});
positions.sort();
var itmer = null;

$('#container').bind('DOMNodeInserted DOMNodeRemoved', function () {
    if (itmer) clearTimeout(itmer);

    itmer = setTimeout(function () {
        var items = viewModel.Items();
        ko.utils.arrayForEach(items, function (item) {
            var index = $('#container [id=' + item.ID() + ']').last().index();
            var newPosition = positions[index];
            item.Position(newPosition);
        });
    }, 50);

});

См. скрипку

Я надеюсь, что это помогает.

person Damien    schedule 22.06.2013
comment
Должен признать, тебе удалось заставить это работать так, как я и не думал. Тем не менее, ответ RP Niemeyer ниже выглядит чище и будет работать во всех браузерах. - person Brad Bamford; 22.06.2013