Как мне поменять местами два элемента в массиве observableArray?

У меня есть кнопка, которая перемещает элемент на одну позицию влево в observableArray. Я делаю это следующим образом. Однако недостатком является то, что category () [index] удаляется из массива, что исключает любые манипуляции с DOM (путем проверки jQuery в моем случае) на этом узле.

Есть ли способ поменять местами два элемента без использования временной переменной, чтобы сохранить узел DOM?

<code>    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");
    }
</code>

Ответы на вопрос(4)

Решение Вопроса

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 все равно будет рассматривать своп как действие удаления и добавления. Естьоткрытый вопрос Нокаут для поддержки движущихся предметов, хотя.Update: Начиная с версии 2.2.0, Knockout распознает перемещенные элементы иforeach переплет не будет повторно отображать их.

 20 дек. 2015 г., 23:39
спасибо большое, вотmoveDown примерstackoverflow.com/a/22348385/287084

брось на мои вещи. Мое решение стало использовать шаблоны knockoutjs для привязки событий beforeRemove и afterAdd к модели. Класс / функция Person также является простой моделью вида нокаута.

В приведенном ниже примере я использую .draggable (), но вы можете легко использовать проверку. Добавьте свой собственный код для манипулирования массивом observableArray, и все будет хорошо.

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());
 24 апр. 2012 г., 10:28
В моем примере я просто повторно добавляю перетаскиваемый объект в вашем случае проверки, когда элемент повторно добавляется в DOM. В моем случае нет необходимости сохранять какие-либо переменные состояния (они все в модели), поэтому это работает для меня. Разве проверка не должна быть такой же?
 Jeow Li Huan24 апр. 2012 г., 10:12
Можете уточнить? То, что я пытаюсь сделать, это использовать кнопки, чтобы позволить пользователю сортировать (может реализовать перетаскивание позже). Как обработка beforeRemove, afterAdd сохраняет элементы DOM? Элементы DOM были сгенерированы Knockout, но были изменены с помощью проверки jQuery, и я теряю изменения, удаляя и затем повторно вставляя элемент.

Майкл Бест для его версии продвижения

моя версия 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]);
    }
}
 05 февр. 2016 г., 18:41
Ваша версия не работает правильно. Замена "arr.length" с "array.length - 1" делает трюк.

что этот ответ приходит с некоторым опозданием, но я подумал, что он может быть полезен для тех, кто хочет более общего решения своп. Вы можете добавить функцию подкачки в ваши observableArrays следующим образом:

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);
    }
}

Ваш ответ на вопрос