简体   繁体   中英

Reorder items in a list using Knockout JS

I have an observable array of items. One of the properties of an 'item' is 'position', which denotes the item's position in the list. I would like to be able to reorder items on the page by having a drop-down with positions next to each item. When a user selects a position for an item in the drop down, the position values for any items affected get recalculated.

The problem that I'm running into is when I attempt to utilize the event binding for the drop down - I can't figure out a way to pass the original & new positions to my 'reposition' function.

I'm sure this could be accomplished by using array indexes for this simple example, but I'm trying to see if I can avoid that.

JSFiddle: http://jsfiddle.net/4tqahpkg/3/

<div class='liveExample'>
<ul data-bind="foreach: orderedItems">
    <li>
        <div>   <span data-bind="text: name"> </span> has Position:
            <select id="pos" data-bind=" options: orderedItems,
                    optionsText: function(item) { return item.position   },
                    optionsValue: function(item){ return item.position   },
                    value: position,
                    event: { change: function () {reposition($data.name(), position()); } } "></select>
        </div>
    </li>
</ul>

var Item = function (name, position) {
    this.name = ko.observable(name);
    this.position = ko.observable(position);

}

var viewModel = function () {
    var self = this;

    this.items = [
    new Item("item Three", "3"),
    new Item("item One", "1"),
    new Item("item Two", "2"),
    new Item("item Five", "5"),
    new Item("item Four", "4"),
    new Item("item Six", "6")];


    self.orderedItems = ko.computed(function () {

        return ko.utils.arrayFilter(this.items, function (item) {
            return true;
        }).sort(function (a, b) {
            var value1 = "",
                value2 = "";
            value1 = a.position() ? a.position() : "";
            value2 = b.position() ? b.position() : "";
            return value1 == value2 ? 0 : (value1 < value2 ? -1 : 1);
        });
    });

    self.curName = ko.observable();

    self.curItem = ko.computed(function (name) {
        return ko.utils.arrayFilter(this.items, function (item) {
            return item.name() == self.curName();
        });
    });

    self.reposition = function (name, newPosition) {

        self.curName(name);
        origPosition = self.curItem()[0].position();

        if (origPosition < newPosition) {
            for (var x = 0; x < orderedItems.length; x++) {
                if (origPosition < newPosition && self.orderedItems()[x].position() >= origPosition && self.orderedItems()[x].position() < newPosition) {
                    self.orderedItems()[x].position(self.orderedItems()[x].position() - 1);
                }

                if (origPosition > newPosition && self.orderedItems()[x].position() >= newPosition && self.orderedItems()[x].position() < origPosition) {
                    self.orderedItems()[x].position(self.orderedItems()[x].position() + 1);
                }

                if (self.orderedItems().name() == name) {
                    self.orderedItems()[x].position(newPosition);
                }
            }
        }
    };


};

ko.applyBindings(viewModel);

You want to access the old position, but you haven't defined any storage for it. Each item will have to have an oldPosition variable (I've made a private one) and have a subscription on position that calls your reposition function before updating oldPosition.

I've done a little re-architecting of your design, which I thought was a bit convoluted. I haven't implemented reposition , which I guess you want to shift other items' positions so you don't have duplicates.

 var viewModel = function() { var self = this; var Item = function(name, pos) { this.name = ko.observable(name); this.position = ko.observable(pos); var oldPosition = pos; this.position.subscribe(function(newValue) { self.reposition(this, oldPosition, newValue); oldPosition = newValue; }, this); }; this.items = [ new Item("item Three", "3"), new Item("item One", "1"), new Item("item Two", "2"), new Item("item Five", "5"), new Item("item Four", "4"), new Item("item Six", "6") ]; self.orderedItems = ko.computed(function() { return ko.utils.arrayFilter(this.items, function(item) { return true; }).sort(function(a, b) { return a.position() - b.position(); }); }); self.curName = ko.observable(); self.reposition = function(item, oldPosition, newPosition) { console.debug("Reposition", item, oldPosition, newPosition); }; }; ko.applyBindings(viewModel); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <div class='liveExample'> <ul data-bind="foreach: orderedItems"> <li> <div> <span data-bind="text: name"> </span> has Position: <select id="pos" data-bind=" options: orderedItems, optionsText: 'position', optionsValue: 'position', value: position "></select> </div> </li> </ul> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM