在Knockout中对可观察数组进行排序

时间:2012-10-04 00:16:39

标签: knockout.js

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

<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 个答案:

答案 0 :(得分:99)

KnockoutJS可观察数组提供了一个排序函数,这使得在UI中对数据绑定数组进行排序相对容易(无论数据的自然顺序如何。)

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

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

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

而不是“l.lastName()&gt; r.lastName()?1:-1”考虑以下内容:

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

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

  1. 姓氏是否等于?
  2. 如果是,请比较名字并返回结果。
  3. 否则,比较姓氏并返回结果。
  4. 我已经扫描了你的代码,我发现没有这样的排序功能。

    这与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)"
    

答案 1 :(得分:3)

如果你确定你的players.json返回已排序的名字,你会没事的。如果它是从数据库加载它们,则需要将第一个名称字段添加到ORDER BY子句中。

如果您想在Javascript中进行排序,可以在从服务加载后立即执行:

players.sort(function(player1, player2) {
    return player1.lastname.localeCompare(player2.lastname) ||
        player1.firstname.localeCompare(player2.firstname);
});

答案 2 :(得分: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. 将该请求的结果排序到您选择的数组中

答案 3 :(得分:-4)

你必须使用两种方法来做到这一点。在第一次排序时,根据人的姓氏进行排序和在第二次排序中首先根据姓氏进行搜索如果超过两个人具有相同的姓氏,则按照他们的名字对这些进行排序在他们的位置,使用一些标准排序算法......