Knockout Observed array with sorting and data binding

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. :)

+7
sorting arrays foreach computed-observable
source share
2 answers

In your JS Fiddle, this is because your foreach is attached to people ... not to sort people.

The reason for sorting it for the first time is because the calculated calculations are done once ... but they are not signed.

However, the calculation ends again when you use parentheses due to some subscription to the underlying array.

Edit:

When you use parentheses, the computed subscribes to the array when the observable is called. When the signed item changes, the calculation is repeated.

+1
source share

The problem of using sorting in views is not really recommended by KO, because with this approach, ObsableArray.sort does not establish a dependency in the array, so the binding will not be updated.

So, if you want to do this, you can use

 items.slice(0).sort() 

for a more detailed view https://github.com/knockout/knockout/issues/1380

Fiddle: http://jsfiddle.net/mbest/6dmAn/

+2
source share

All Articles