66

人物オブジェクトのノックアウトに観測可能な配列があります。家系の名前に基づいて人のリストを並べ替えることができるようにしたかったのです。問題は、リストに重複する姓が多数あることです。その結果、複数の名前が存在する場合、名前は見つかったとおりに表示されます。配列を名前で並べ替えることができるようにしたいのですが、名前が複数ある場合は、名前でも並べ替えてもらいます。ユーザーが姓の入力を開始するためのテキスト入力を使用しています。結果は、すべての一致を表示するテンプレートにバインドされます。

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

そして、これが私のノックアウト配列フィルターコードです:

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);
    });    
});

家系の名前のフィルタリングではこれは問題なく機能しますが、名前が重複している場合に名前の並べ替えを追加する方法を見つけることができません。たとえば、私の配列で名前で並べ替えると、次のようになります。

Joe Bailey
Jack Brown
Adam Brown
Bob Brown
Jim Byrd

重複する家系の名前にも名前を並べ替えてもらいたいのですが、次のようになります。

Joe Bailey
Adam Brown
Bob Brown
Jack Brown
Jim Byrd
4

4 に答える 4

107

KnockoutJS の監視可能な配列はソート機能を提供します。これにより、(データの自然な順序に関係なく) UI でデータバインドされた配列を比較的簡単にソートできます。

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

ソースデータを事前に並べ替え/再並べ替えする必要はありません。バインドする前に並べ替える (または並べ替えのために再バインドする) 場合は、間違っています。

そうは言っても、あなたが求めているのは、姓、名の2つのデータでソートすることです。

「l.lastName() > r.lastName() ? 1 : -1」の代わりに、次のことを考慮してください。

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

これはもっと効率的かもしれません、私は確信しています。基本的に、次の 3 つの条件があります。

  1. 苗字は同じですか?
  2. その場合は、名前を比較して結果を返します。
  3. それ以外の場合は、姓を比較して結果を返します。

あなたのコードをスキャンしましたが、そのようなソート機能はありません。

これはMichael Bestの回答に似ていますが、ソートを処理する場所(バインディング、最初の例)と、探しているソートを実現する方法(複数のデータ)を明確にしようとしました。

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) })"

当然のことながら、反転や追加のデータなど、より多くの並べ替えベクトルを導入すると、これは扱いにくくなる可能性があるため、上記の評価を実行するフィルター関数を実装する必要があります。

data-bind="foreach: items().sort(my.utils.compareItems)"
于 2013-01-25T00:21:06.167 に答える
3

players.jsonソートされた名前が返されることを確認すれば、問題ありません。ORDER BYデータベースからロードしている場合は、名フィールドを句に追加する必要があります。

Javascript で並べ替えを行いたい場合は、サービスからロードした直後に行うことができます。

players.sort(function(player1, player2) {
    return player1.lastname.localeCompare(player2.lastname) ||
        player1.firstname.localeCompare(player2.firstname);
});
于 2012-10-04T00:31:33.743 に答える
-4

これを行うには、2 つの並べ替えを使用する必要があります。最初の並べ替えでは、人の姓に従って並べ替え、2 つ目の並べ替えでは、最初に姓に従って検索します、いくつかの標準ソートアルゴリズムを使用して....

于 2014-01-16T11:44:04.650 に答える