I would like to have an observable array which will sort itself when an object is pushed into it (it would be even better if it would sort itself if any of the values it was using in the comparator function was changed).
Something where you could define the comparator function you want the array to sort on and then every time push was called it would add the pushed objects into the correct place in the array so the array remained sorted, like:
var sortedArray = ko.sortedObservableArray(
function (a,b) { return b - a;},
[1,7,4]
); // sortedArray will be [1,4,7]
sortedArray.push([5,2]); // sortedArray will now be [1,2,4,5,7]
Are there any libraries that will do this for me and if not what is the best way to go about implementing this?
I ended up creating a sorted observable array by extending knockout observable array:
ko.sortedObservableArray = function (sortComparator, initialValues) {
if (arguments.length < 2) {
initialValues = [];
}
var result = ko.observableArray(initialValues);
ko.utils.extend(result, ko.sortedObservableArray.fn);
delete result.unshift;
result.sort(sortComparator);
return result;
};
ko.sortedObservableArray.fn = {
push: function (values) {
if (!$.isArray(values)) {
values = [values];
}
var underlyingArray = this.peek();
this.valueWillMutate();
underlyingArray.push.apply(underlyingArray, values);
underlyingArray.sort(this.sortComparator);
this.valueHasMutated();
},
sort: function (sortComparator) {
var underlyingArray = this.peek();
this.valueWillMutate();
this.sortComparator = sortComparator;
underlyingArray.sort(this.sortComparator);
this.valueHasMutated();
},
reinitialise: function (values) {
if (!$.isArray(values)) {
values = [values];
}
var underlyingArray = this.peek();
this.valueWillMutate();
underlyingArray.splice(0, underlyingArray.length);
underlyingArray.push.apply(underlyingArray, values);
underlyingArray.sort(this.sortComparator);
this.valueHasMutated();
},
reverse: function () {
var underlyingArrayClone = this.peek().slice();
underlyingArrayClone.reverse();
return underlyingArrayClone;
}
};
Which can be used in the following way:
var sortedArray = ko.sortedObservableArray(
function (a,b) { return a - b;},
[1,7,4]
); // sortedArray will be [1,4,7]
sortedArray.push([5,2]); // sortedArray will now be [1,2,4,5,7]
sortedArray.sort(function (a,b){
return b - a;
}); // sortedArray will now be [7,5,4,2,1]
sortedArray.push(6); // sortedArray will now be [7,6,5,4,2,1]
The only problem I have is that when reinitialising the sorted observable array with a new array in the same way you would reinitialise an observable array the sorted observable array isn't being sorted. To get around this I have added a reinitialise function on the sorted observable array:
var sortedArray = ko.sortedObservableArray(
function (a,b) { return a - b;},
[1,7,4]
); // sortedArray will be [1,4,7]
sortedArray([3,2,8]); // this doesn't work correctly, sortedArray will be [3,2,8]
// instead of [2,3,8]
// To get around this you can use reinitialise()
sortedArray.reinitialise([3,2,8]); // sortedArray will be [2,3,8]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With