Con Backbone.js J'ai mis en place une collection avec une fonction de comparaison. Elle trie bien les modèles, mais j'aimerais inverser l'ordre. Comment puis-je faire en sorte que les modèles soient triés de manière descendante plutôt qu'ascendante ?
Réponses
Trop de publicités?Eh bien, vous pouvez renvoyer des valeurs négatives du comparateur. Si nous prenons, par exemple, l'exemple du site de Backbone et que nous voulons inverser l'ordre, cela ressemblera à ceci :
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
chapters.comparator = function(chapter) {
return -chapter.get("page"); // Note the minus!
};
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
alert(chapters.pluck('title'));
Personnellement, je ne suis pas très satisfait des solutions proposées ici :
-
La solution consistant à multiplier par -1 ne fonctionne pas lorsque le type de tri est non numérique. Bien qu'il existe des moyens de contourner ce problème (en appelant
Date.getTime()
par exemple) ces cas sont spécifiques. Je voudrais un moyen général d'inverser le sens de n'importe quel tri, sans avoir à se préoccuper du type spécifique du champ à trier. -
Pour la solution des chaînes de caractères, la construction d'une chaîne de caractères un caractère à la fois semble être un goulot d'étranglement en termes de performances, en particulier lors de l'utilisation de grandes collections (ou en fait, de grandes chaînes de champs de tri).
Voici une solution qui fonctionne bien pour les champs de type String, Date et Numérique :
Tout d'abord, déclarez un comparateur qui inversera le résultat d'un résultat d'une fonction sortBy, comme ceci :
function reverseSortBy(sortByFunction) {
return function(left, right) {
var l = sortByFunction(left);
var r = sortByFunction(right);
if (l === void 0) return -1;
if (r === void 0) return 1;
return l < r ? 1 : l > r ? -1 : 0;
};
}
Maintenant, si vous voulez inverser la direction du tri, tout ce que nous devons faire est :
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
// Your normal sortBy function
chapters.comparator = function(chapter) {
return chapter.get("title");
};
// If you want to reverse the direction of the sort, apply
// the reverseSortBy function.
// Assuming the reverse flag is kept in a boolean var called reverseDirection
if(reverseDirection) {
chapters.comparator = reverseSortBy(chapters.comparator);
}
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
alert(chapters.pluck('title'));
La raison pour laquelle cela fonctionne est que Backbone.Collection.sort
se comporte différemment si la fonction de tri a deux arguments. Dans ce cas, elle se comporte de la même manière que le comparateur passé dans la fonction Array.sort
. Cette solution fonctionne en adaptant la fonction sortBy à un seul argument en un comparateur à deux arguments et en inversant le résultat.
Le comparateur de collections de Backbone.js s'appuie sur la méthode Underscore.js _.sortBy. La manière dont sortBy est implémentée finit par "envelopper" javascript .sort() d'une manière qui rend difficile le tri des chaînes de caractères en sens inverse. La simple négation de la chaîne renvoie NaN et interrompt le tri.
Si vous avez besoin d'effectuer un tri inversé avec des chaînes de caractères, par exemple un tri alphabétique inversé, voici un moyen très simple de le faire :
comparator: function (Model) {
var str = Model.get("name");
str = str.toLowerCase();
str = str.split("");
str = _.map(str, function(letter) {
return String.fromCharCode(-(letter.charCodeAt(0)));
});
return str;
}
Ce n'est pas du tout joli, mais c'est un "négateur de chaîne". Si vous n'avez aucun scrupule à modifier les types d'objets natifs en javascript, vous pouvez rendre votre code plus clair en extrayant le négateur de chaîne et en l'ajoutant comme méthode sur String.Prototype. Cependant, vous ne voudrez probablement le faire que si vous savez ce que vous faites, car la modification des types d'objets natifs en javascript peut avoir des conséquences imprévues.
Ma solution était d'inverser les résultats après le tri.
Pour éviter la double équarrissage, il faut d'abord trier en mode silencieux, puis déclencher la "réinitialisation".
collections.sort({silent:true})
collections.models = collections.models.reverse();
collections.trigger('reset', collections, {});
Modifiez votre fonction de comparaison pour qu'elle renvoie une valeur proportionnelle inverse au lieu de renvoyer les données que vous avez actuellement. Un peu de code de : http://documentcloud.github.com/backbone/#Collection-comparator
Exemple :
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
/* Method 1: This sorts by page number */
chapters.comparator = function(chapter) {
return chapter.get("page");
};
/* Method 2: This sorts by page number in reverse */
chapters.comparator = function(chapter) {
return -chapter.get("page");
};
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));