I have an array of objects that are connected to an observable knockout array. I needed to apply sorting to these arrays, and I came across some behavior that is a bit confusing.
My first attempt was to apply sorting in data binding foreach.
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)})">
Performs the correct sort, but I lose the ability to dynamically add / remove elements from the array and update the DOM.
If I add a set of brackets to access the base JavaScript array, everything will be 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 of the SO answers I found, I ended up creating a calculated 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 bind the data to the calculated observable, since it runs immediately. I can click and delete array elements and DOM updates accordingly.
However, if I changed 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 can push elements to the array and DOM updates, but the data is not sorted.
I think these differences are related to tracking the knockout dependencies and the difference between working on the observed array and the native JavaScript array under it, but it's hard for me to understand why the behavior is changing. I can make it work, but I'm also curious about what is considered best practice.
Thanks for any help. :)