66

我在人员对象的淘汰赛中有一个可观察的数组。我希望能够根据姓氏对人员列表进行排序。问题是列表中有许多重复的姓氏。结果是,当有多个姓氏时,第一个名字会在找到时出现。我希望能够按姓氏对数组进行排序,当有多个姓氏时,也可以按名字排序。我正在使用文本输入让用户开始输入姓氏。结果绑定到显示所有匹配项的模板。

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

这是我的 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);
    });    
});

对于姓氏过滤,这很好用,但是当有重复的姓氏时,我无法找到添加排序名字的方法。例如,在我的数组中按姓氏排序时,我得到:

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

您不必对源数据进行预排序/重新排序,如果您在绑定之前进行排序(或由于排序而重新绑定),那么您做错了。

也就是说,你要问的是按两个数据排序,姓氏,然后是名字。

而不是 "l.lastName() > r.lastName() ? 1 : -1" 考虑以下内容:

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

我敢肯定,这可能会更有效率。基本上你有三个条件在起作用:

  1. 姓氏是否相等?
  2. 如果是这样,比较名字并返回结果。
  3. 否则,比较姓氏并返回结果。

我已经扫描了您的代码,但没有看到这样的排序功能。

这类似于 Michael Best 的回答,但是,我试图澄清 WHERE 处理排序(在您的绑定中,第一个示例中)以及如何实现您正在寻找的排序(多个数据。)

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 回答
0

我在尝试对可观察数组进行排序时遇到了一些问题,我在代码中没有看到任何结果。

在将新项目返回到数组之前,您需要先对通过 ajax/getJSON 请求收到的结果进行排序。

这样,在将结果作为新项目添加到您的可观察数组之前对其进行排序。不需要在绑定处对它们进行排序。

请参见下面的示例。

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);
            }));
  1. 使用 AJAX / getJSON 获取数据
  2. 将该请求的结果排序到您选择的数组中
于 2017-01-20T07:35:48.293 回答
-4

您必须使用两次排序来执行此操作。在第一次排序中,根据人的姓氏进行排序,在第二次排序中,如果有两个以上的人具有相同的姓氏,则首先根据姓氏进行搜索,而不是根据他们所在位置的名字进行排序,使用一些标准排序算法....

于 2014-01-16T11:44:04.650 回答