64 votes

Tri d'un tableau d'observables en Knockout

J'ai un tableau observable dans Knockout d'objets de personnes. Je voulais être en mesure de trier la liste des personnes en fonction du nom de famille. Le problème est que la liste contient un certain nombre de noms de famille en double. Le résultat est que lorsqu'il y a plus d'un nom de famille, les prénoms apparaissent tels qu'ils ont été trouvés. J'aimerais pouvoir trier le tableau par nom de famille et, lorsqu'il y a plus d'un nom de famille, le trier également par prénom. J'utilise une entrée de texte pour que l'utilisateur commence à taper le nom de famille. Les résultats sont liés à un modèle qui affiche toutes les correspondances.

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

Et voici mon code de filtre de tableau 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);
    });    
});

Pour le filtrage des noms de famille, cela fonctionne bien, mais je ne parviens pas à trouver un moyen d'ajouter le tri du prénom lorsqu'il y a des noms de famille en double. Par exemple, dans mon tableau, lorsque le tri est effectué par nom de famille, j'obtiens :

Joe Bailey
Jack Brown
Adam Brown
Bob Brown
Jim Byrd

J'aimerais que les noms de famille en double soient également triés par prénom :

Joe Bailey
Adam Brown
Bob Brown
Jack Brown
Jim Byrd

102voto

Shaun Wilson Points 2363

Les tableaux observables de KnockoutJS offrent une fonction de tri, ce qui rend relativement facile le tri d'un tableau lié à des données dans votre interface utilisateur (indépendamment de l'ordre naturel des données).

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

Vous ne devriez pas avoir à trier/re-trier au préalable vos données sources. Si vous triez avant de lier (ou de relier à nouveau en raison d'un tri), vous vous y prenez mal.

Cela dit, ce que vous demandez, c'est de trier par deux données, le nom de famille, puis le prénom.

Au lieu de "l.lastName() > r.lastName() ? 1 : -1", considérez ce qui suit :

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

Cela pourrait être plus efficace, j'en suis sûr. En fait, vous avez trois conditions en jeu :

  1. Les noms de famille sont-ils égaux ?
  2. Si oui, comparez les prénoms et renvoyez un résultat.
  3. Sinon, comparer les noms de famille et renvoyer un résultat.

J'ai scanné votre code et je ne vois aucune fonction de ce type en place.

Cette réponse est similaire à celle de Michael Best, mais j'ai tenté de préciser OÙ il faut traiter le tri (dans votre liaison, premier exemple) et COMMENT obtenir le tri que vous recherchez (données multiples).

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

Naturellement, cela peut devenir difficile à gérer si vous introduisez davantage de vecteurs de tri, tels que des inversions ou des données supplémentaires, et vous devez donc implémenter une fonction de filtre qui effectue l'évaluation ci-dessus pour vous :

data-bind="foreach: items().sort(my.utils.compareItems)"

3voto

Michael Best Points 9033

Si vous vous assurez que votre players.json retourne les noms triés, vous serez bien. S'il les charge à partir d'une base de données, vous devez ajouter le champ du prénom à votre fichier ORDER BY clause.

Si vous voulez faire le tri en Javascript, vous pouvez le faire juste après avoir chargé le service :

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

-4voto

sonu Points 21

Vous devez utiliser deux tris pour faire cela. Dans le premier tri, trier selon le nom de famille des personnes et dans le second tri, rechercher d'abord selon le nom de famille si plus de deux personnes ont le même nom de famille, alors trier ces personnes selon leur prénom à leur emplacement, en utilisant un algorithme de tri standard .....

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X