简体   繁体   中英

knockout.js not sorting observable array

I for the life of me can't get this array to sort appropriately. I know the sort function works but the timing of some sort is off. Can't seem to figure it out.

UI

 <!-- ko foreach: Times.sort(function (l, r) { app.utils.orderTime(l.Time(), r.Time()); }) -->

Javascript

function Day(date, updated) {

        var self = this;

        self.Times = ko.observableArray([]);

        var times = ko.utils.arrayMap(date.Times, function (item) {
            return new Time(item, updated);
        });

        self.Times.push.apply(self.Times, times);
    }

Sort Function

app.utils.orderTime = function(l, r) {  // l = "9:00 AM", r = "11:00 PM"
    var leftFormatted = new Date('1/1/2012 ' + l); // Sun Jan 01 2012 09:00:00 GMT-0700
    var rightFormatted = new Date('1/1/2012 ' + r); // Sun Jan 01 2012 23:00:00 GMT-0700

    return leftFormatted.compareTo(rightFormatted); // -1
};

UPDATE:

I went ahead and added a computed called TimeSorted and sorts great, but I cant push anything into the time array and have it updated unless I have self.Times().sort( ... instead but then the order isnt kept.

        self.TimesSorted = ko.computed(function() {
            return self.Times.sort(function (l, r) { app.utils.orderTime(l.Time(), r.Time()); });
        });

 <!-- ko foreach: TimesSorted -->

The sort method modifies the array it acts on and thus changes the original array. The fact that it also returns that array is what confuses a lot of people. A binding like this shouldn't be modifying the array; it should be working with a copy of the array:

<!-- ko foreach: Times.slice(0).sort(...) -->

The observable array sort method changes the array (just like push , splice , etc.) and notifies subscribers of the change. It doesn't create a dependency on the array within a binding or computed observable. The slice method, on the other hand, does create a dependency.

If you really do want to sort the original array, this really shouldn't be done in a binding. I suggest you use an extender such as this:

ko.extenders.sorted = function (obs, sortFunction) {
    obs.sort(sortFunction);
    obs.subscribe(function (array) {
        array.sort(sortFunction);
    });
}

...

self.Times = ko.observableArray([]).extend({ sorted: function (l, r) { return app.utils.orderTime(l.Time(), r.Time()); } });

Example: http://jsfiddle.net/mbest/f3SX2/

Geez I feel a dumb. I wasn't returning anything in the sort function of the array, just called a method. This fixed it and I add to add () to the observable array.

<!-- ko foreach: Times().sort(function (l, r) { return app.utils.orderTime(l.Time(), r.Time()); }) -->

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