I have an array of objects that are hooked up into a knockout observable array. I needed to apply sorting to these arrays and I ran into some behavior that is a bit confusing.
My first attempt involved applying the sort in the foreach data-binding.
http://jsfiddle.net/wnfXV/
<ul data-bind="foreach: people.sort(function(l,r) { return l.name == r.name ? 0 : (l.name < r.name ? -1 : 1)})">
This performs the proper sorting, but I lose the ability to dynamically add/remove elements from the array and have the DOM update.
If I add a set of parenthesis to access the underlying JavaScript array, everything works fine.
<ul data-bind="foreach: people().sort(function(l,r) { return l.name == r.name ? 0 : (l.name < r.name ? -1 : 1)})">
Based on some SO answers I found, I ended up creating a computed observable for the sorted array. http://jsfiddle.net/wnfXV/2/
self.sortedPeople = ko.computed(function() {
return self.people().sort(function(l,r) {
return l.name == r.name ? 0 : (l.name < r.name ? -1 : 1);
});
});
This also works. And I don't even need to data-bind to the computed observable since it is executed immediately. I can push and remove array items and the DOM updates appropriately.
However, if I change the code to:
self.sortedPeople = ko.computed(function() {
return self.people.sort(function(l,r) {
return l.name == r.name ? 0 : (l.name < r.name ? -1 : 1);
});
});
Now, I am able to push items to the array and the DOM updates, but the data is not being sorted.
I think these differences are related to knockout dependency tracking, and the difference between operating on an observable array and the native JavaScript array underneath it, but I'm having a hard time conceptualizing why the behavior is changing. I am able to get it to work, but I'm also curious as to what is considered best practice.
Thanks for any help. :)
Problem with using sort in views is actually not recommended by KO because
with this approach observableArray.sort doesn't establish a dependency on the array, so the binding won't get updated.
So if you want to make it work one can use
items.slice(0).sort()
for more detailed look at
https://github.com/knockout/knockout/issues/1380