web-dev-qa-db-fra.com

Tri d'un tableau observable dans Knockout

J'ai un tableau observable dans Knockout of person objects. Je voulais pouvoir trier la liste des personnes en fonction du nom de famille. Le problème est que la liste contient plusieurs 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, quand il y a plus d'un nom de famille, le trier aussi 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 à ajouter de tri au prénom lorsqu'il existe des noms de famille en double. Par exemple, dans mon tableau une fois trié par nom de famille, je reçois:

Joe Bailey
Jack Brown
Adam Brown
Bob Brown
Jim Byrd

J'aimerais que les noms de famille en double aient également leurs prénoms triés:

Joe Bailey
Adam Brown
Bob Brown
Jack Brown
Jim Byrd
60
user1715156

Les tableaux observables KnockoutJS offrent une fonction de tri, ce qui le rend relativement facile à trier un tableau lié aux données dans votre interface utilisateur (quel que soit 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 à pré-trier/re-trier vos données source, si vous triez avant la liaison (ou la ré-association en raison d'un tri), alors vous le faites mal.

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

Au lieu de "l.lastName ()> r.lastName ()? 1: -1", tenez compte des éléments suivants:

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. Fondamentalement, vous avez trois conditions en jeu:

  1. Les noms de famille sont-ils égaux?
  2. Si tel est le cas, comparez les prénoms et renvoyez un résultat.
  3. Sinon, comparez les noms de famille et renvoyez un résultat.

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

Ceci est similaire à la réponse de Michael Best, cependant, j'ai essayé de clarifier les endroits où gérer le tri (dans votre reliure, premier exemple) et COMMENT atteindre 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 fastidieux à mesure que vous introduisez plusieurs vecteurs de tri, tels que des inversions ou des données supplémentaires, et vous devez donc implémenter une fonction de filtrage qui effectue l'évaluation ci-dessus à votre place:

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

Si vous vous assurez que votre players.json renvoie les noms triés, tout ira bien. S'il s'agit de les charger depuis une base de données, vous devez ajouter le champ prénom à votre clause ORDER BY.

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

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

J'ai eu quelques problèmes pour essayer de trier un tableau observable, je ne voyais aucun résultat dans mon code. 

Vous devez d'abord trier les résultats que vous recevez via une requête ajax/getJSON avant de renvoyer les nouveaux éléments dans votre tableau. 

De cette façon, les résultats sont triés avant d'être ajoutés à votre tableau observable en tant que nouveaux éléments. Pas besoin de les trier aux fixations alors.

Voir l'exemple ci-dessous.

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. obtenir des données en utilisant AJAX/getJSON
  2. Triez le résultat de cette requête dans votre tableau de choix
0
Ettore Raimondi