Как поменять два элемента в наблюдаемом массиве?
У меня есть кнопка, которая перемещает элемент в одну позицию слева в наблюдаемом массиве. Я делаю это следующим образом. Однако недостаток заключается в том, что категории() [index] удаляются из массива, тем самым отбрасывая любые манипуляции с DOM (с помощью проверки jQuery в моем случае) на node.
Есть ли способ обменять два элемента без использования временной переменной, чтобы сохранить DOM node?
moveUp: function (category) {
var categories = viewModel.categories;
var length = categories().length;
var index = categories.indexOf(category);
var insertIndex = (index + length - 1) % length;
categories.splice(index, 1);
categories.splice(insertIndex, 0, category);
$categories.trigger("create");
}
Ответы
Ответ 1
Здесь моя версия moveUp
, которая выполняет свопинг за один шаг:
moveUp: function(category) {
var i = categories.indexOf(category);
if (i >= 1) {
var array = categories();
categories.splice(i-1, 2, array[i], array[i-1]);
}
}
Это все еще не решает проблему, потому что Knockout по-прежнему будет видеть своп как действие delete и add. Там открытая проблема для нокаута для поддержки движущихся объектов. Обновление: Начиная с версии 2.2.0, Knockout распознает перемещенные элементы, а привязка foreach
не будет повторно отображать их.
Ответ 2
Я знаю, что этот ответ приходит немного позже, но я подумал, что это может быть полезно для других, которым требуется более общее решение для свопинга. Вы можете добавить функцию свопинга в ваши наблюдаемые массивы, например:
ko.observableArray.fn.swap = function(index1, index2) {
this.valueWillMutate();
var temp = this()[index1];
this()[index1] = this()[index2];
this()[index2] = temp;
this.valueHasMutated();
}
Затем вы можете использовать эту функцию для замены двух элементов в массиве с учетом их индексов:
myArray.swap(index1, index2);
Для функции moveUp вы можете сделать что-то вроде этого:
moveUp: function(category) {
var i = categories.indexOf(category);
if (i > 0) {
categories.swap(i, i+1);
}
}
Ответ 3
У меня была аналогичная проблема, так как я хотел, чтобы jQuery перетаскивал мои элементы.
Мое решение стало использовать шаблоны knockoutjs для привязки событий beforeRemove и afterAdd к модели. Класс/функция Person также представляет собой простую модель представления нокаутов.
В приведенном ниже примере я использую .draggable(), но вы можете легко использовать проверку. Добавьте свой собственный код для управления наблюдаемым массивом, и вам должно быть хорошо идти.
HTML:
<div data-bind="template: {foreach:attendeesToShow, beforeRemove:hideAttendee, afterAdd:showAttendee}">
<div class="person">
<img src="person.jpg" alt="" />
<div data-bind="text: firstName" ></div>
<div class="deleteimg" data-bind="click:$parent.removeAttendee" title="Remove"></div>
</div>
</div>
ViewModel:
var ViewModel = function () {
var self = this;
var at = [new Person('First', 'Person', '[email protected]'),
Person('Second', 'Person', '[email protected]')
];
self.attendees = ko.observableArray(at);
self.removeAttendee = function (attendee) {
self.attendees.remove(attendee);
};
this.showAttendee = function (elem) {
if (elem.nodeType === 1) {
$(elem).hide().show("slow").draggable();//Add jQuery functionality
}
};
this.hideAttendee = function (elem) {
if (elem.nodeType === 1) {
$(elem).hide(function () {
$(elem).remove();
});
}
};
};
ko.applyBindings(new ViewModel());
Ответ 4
благодаря Michael Best за его версию moveup
моя версия moveDown
moveDown: function(category) {
var array = categories();
var i = categories.indexOf(category);
if (i < arr.length) {
categories.splice(i, 2, array[i + 1], array[i]);
}
}