Sort the observed array by knockout

I have an observable array in the knockout of human objects. I wanted to be able to sort the list of persons by last name. The problem is that there are several duplicate last names in the list. As a result, when there is more than one last name, the first names appear as they are found. I would like to be able to sort the array by last name and, when there is more than one last name, try also sorting by first name. I use text input for the user to start typing the last name. Results are tied to a template that displays all matches.

<input data-bind="value: filter, valueUpdate: 'afterkeydown'">

And here is my filter filter for knockout:

 function Item(firstname, lastname) { this.firstname = ko.observable(firstname); this.lastname = ko.observable(lastname); } var playersViewModel = { items: ko.observableArray([]), filter: ko.observable("") }; var players; $(function() { playersViewModel.filteredItems = ko.computed(function() { var filter = this.filter().toLowerCase(); if (!filter) { return this.items(); } else { return ko.utils.arrayFilter(this.items(), function(item) { return ko.utils.stringStartsWith(item.lastname().toLowerCase(), filter); }); } }, playersViewModel); $.getJSON('./players.json', function(data) { players = data.players; playersViewModel.players = ko.observableArray(players); ko.applyBindings(playersViewModel); var mappedData = ko.utils.arrayMap(players, function(item) { return new Item(item.firstname,item.lastname); }); playersViewModel.items(mappedData); }); }); 

This works fine for filtering a name, but I cannot find a way to add a name to the sort when there are duplicate names. For example, in my array, when sorting by name, I get:

 Joe Bailey Jack Brown Adam Brown Bob Brown Jim Byrd 

I would like duplicate name names to also sort by name:

 Joe Bailey Adam Brown Bob Brown Jack Brown Jim Byrd 
+59
04 Oct
source share
4 answers

KnockoutJS observable arrays offer a sorting function, so it is relatively easy to sort a data array in your user interface (regardless of the natural order of the data).

 data-bind="foreach: items.sort(function (l, r) { return l.lastName() > r.lastName() ? 1 : -1 })" 

You do not need to pre-sort / re-sort the original data, if you sort before binding (or re-sorting due to sorting) then you are doing it wrong.

However, what you ask for is sorting by two values, last name, then first name.

Instead of "l.lastName ()> r.lastName ()? 1: -1", consider the following:

 l.lastName() === r.lastName() ? l.firstName() > r.firstName() ? 1 : -1 : l.lastName() > r.lastName() ? 1 : -1 

It may be more effective, I'm sure. Basically, you have three conditional expressions:

  • Are the last names equal?
  • If so, compare the names and return the result.
  • Repeat, compare last names and return the result.

I looked at your code and I do not see such sorting function.

This is similar to Michael Best's answer, however, I tried to clarify WHERE in order to handle the sorting (in your example bindings, the first example) and HOW to achieve the view you are looking for (multiple anchor points).

 data-bind="foreach: items().sort(function (l, r) { return (l.lastName() == r.lastName()) ? (l.firstName() > r.firstName() ? 1 : -1) : (l.lastName() > r.lastName() ? 1 : -1) })" 

Naturally, this can become cumbersome as you enter more sorting vectors, such as inverse or additional data, and therefore you must implement a filter function that performs the above assessment for you:

 data-bind="foreach: items().sort(my.utils.compareItems)" 
+93
Jan 25 '13 at 0:21
source share

If you make sure your players.json returns the sorted names, everything will be fine. If it loads them from the database, you need to add the first name field to the ORDER BY .

If you want to do the sorting in Javascript, you can do it right after loading from the service:

 players.sort(function(player1, player2) { return player1.lastname.localeCompare(player2.lastname) || player1.firstname.localeCompare(player2.firstname); }); 
+3
04 Oct
source share

I had problems sorting the observed array, I did not see any results in my code.

First you need to sort the results obtained using the ajax / getJSON request before you return the new elements to your array.

This way the results are sorted before they are added to your observed array as new elements. No need to sort them with bindings.

See the example below.

 players(ko.utils.arrayMap(result, function (item) { result.sort(function (l, r) { return l.name == r.name ? 0 : (l.name < r.name ? -1 : 1); }); return new Player(item); })); 
  • get data using AJAX / getJSON
  • Sort the result of a query into an array of your choice
0
Jan 20 '17 at 7:35
source share

To do this, use two types. In the first sort, sort by the words of the last name and in the second sort, First search by first name, if more than two people have the same last name, than sort by the first name in their location using some standard sorting algorithm ....

-four
Jan 16 '14 at 11:44
source share



All Articles