Mit Backbone.js habe ich eine Sammlung mit einer Komparatorfunktion eingerichtet. Es ist schön, die Modelle zu sortieren, aber ich möchte die Reihenfolge umkehren.
Wie kann ich die Modelle in absteigender Reihenfolge sortieren, anstatt aufsteigend?
Mit Backbone.js habe ich eine Sammlung mit einer Komparatorfunktion eingerichtet. Es ist schön, die Modelle zu sortieren, aber ich möchte die Reihenfolge umkehren.
Wie kann ich die Modelle in absteigender Reihenfolge sortieren, anstatt aufsteigend?
Antworten:
Nun, Sie können negative Werte vom Komparator zurückgeben. Wenn wir zum Beispiel das Beispiel von der Backbone-Site nehmen und die Reihenfolge umkehren möchten, sieht es folgendermaßen aus:
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'));
Persönlich bin ich mit keiner der hier angegebenen Lösungen so zufrieden:
Die Lösung zum Multiplizieren mit -1 funktioniert nicht, wenn der Sortiertyp nicht numerisch ist. Obwohl es Möglichkeiten gibt, dies zu umgehen (indem Sie Date.getTime()beispielsweise anrufen ), sind diese Fälle spezifisch. Ich möchte einen allgemeinen Weg, um die Richtung jeglicher Art umzukehren, ohne mir Gedanken über den spezifischen Typ des zu sortierenden Feldes machen zu müssen.
Für die String-Lösung scheint das Erstellen eines Strings zeichenweise ein Leistungsengpass zu sein, insbesondere bei Verwendung großer Sammlungen (oder großer Sortierfeld-Strings).
Hier ist eine Lösung, die für String-, Datums- und numerische Felder gut funktioniert:
Deklarieren Sie zunächst einen Komparator, der das Ergebnis eines Ergebnisses einer sortBy-Funktion wie folgt umkehrt:
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;
};
}
Wenn Sie nun die Richtung der Sortierung umkehren möchten, müssen wir nur noch Folgendes tun:
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'));
Der Grund dafür ist, dass Backbone.Collection.sortsich das Verhalten anders verhält, wenn die Sortierfunktion zwei Argumente hat. In diesem Fall verhält es sich genauso wie der Komparator Array.sort. Diese Lösung funktioniert, indem die Funktion sortBy für einzelne Argumente in einen Komparator mit zwei Argumenten umgewandelt und das Ergebnis umgekehrt wird.
Der Sammlungskomparator von Backbone.js basiert auf der Underscore.js-Methode _.sortBy. Die Art und Weise, wie sortBy implementiert wird, führt dazu, dass Javascript .sort () so "eingepackt" wird, dass das umgekehrte Sortieren von Zeichenfolgen schwierig wird. Durch einfaches Negieren des Strings wird NaN zurückgegeben und die Sortierung unterbrochen.
Wenn Sie eine umgekehrte Sortierung mit Strings durchführen müssen, z. B. eine umgekehrte alphabetische Sortierung, ist dies eine wirklich hackige Methode:
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;
}
Es ist keineswegs hübsch, aber es ist ein "String Negator". Wenn Sie keine Bedenken haben, native Objekttypen in Javascript zu ändern, können Sie den Code klarer gestalten, indem Sie den String-Negator extrahieren und als Methode für String.Prototype hinzufügen. Sie möchten dies jedoch wahrscheinlich nur tun, wenn Sie wissen, was Sie tun, da das Ändern nativer Objekttypen in Javascript unvorhergesehene Folgen haben kann.
Meine Lösung bestand darin, die Ergebnisse nach dem Sortieren umzukehren.
Um doppeltes Rendern zu verhindern, sortieren Sie zuerst mit Silent und lösen Sie dann 'Reset' aus.
collections.sort({silent:true})
collections.models = collections.models.reverse();
collections.trigger('reset', collections, {});
-Date.getTime(), möglicherweise mit etwas mehr Hacking, wenn Sie glauben, dass Dates in Ihrem System die Unix-Epoche überschreiten werden. In alphabetischer Reihenfolge sehen Sie sich Andrews Antwort oben an.
Ändern Sie Ihre Komparatorfunktion, um einen umgekehrten Proportionalwert zurückzugeben, anstatt die Daten zurückzugeben, die Sie gerade sind. Einige Codes von: http://documentcloud.github.com/backbone/#Collection-comparator
Beispiel:
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"}));
Folgendes hat bei mir gut funktioniert:
comparator: function(a, b) {
// Optional call if you want case insensitive
name1 = a.get('name').toLowerCase();
name2 = b.get('name').toLowerCase();
if name1 < name2
ret = -1;
else if name1 > name2
ret = 1;
else
ret = 0;
if this.sort_dir === "desc"
ret = -ret
return ret;
}
collection.sort_dir = "asc";
collection.sort(); // returns collection in ascending order
collection.sort_dir = "desc";
collection.sort(); // returns collection in descending order
Ich habe einige gelesen, in denen die Backbone-Komparatorfunktion die JavaScript-Funktion Array.prototype.sort () verwendet oder nachahmt. Dies bedeutet, dass entweder 1, -1 oder 0 verwendet wird, um die Sortierreihenfolge für jedes Modell in der Sammlung festzulegen. Dies wird ständig aktualisiert und die Sammlung bleibt in der richtigen Reihenfolge basierend auf dem Komparator.
Informationen zu Array.prototype.sort () finden Sie hier: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?redirectlocale=de-US&redirectslug=JavaScript% 2FReference% 2FGlobal_Objects% 2FArray% 2Fsort
Viele Antworten auf diese Frage kehren einfach die Reihenfolge um, bevor sie auf die Seite gerendert werden. Das ist nicht ideal.
Mit dem obigen Artikel über Mozilla als Leitfaden konnte ich meine Sammlung mit dem folgenden Code in umgekehrter Reihenfolge sortieren. Dann rendern wir die Sammlung einfach in der aktuellen Reihenfolge auf Seite und können ein Flag (reverseSortDirection) zum Umkehren der Reihenfolge verwenden .
//Assuming this or similar will be in your Backbone.Collection.
sortKey: 'id', //The field name of the item in your collection
reverseSortDirection: false,
comparator: function(a, b) {
var sampleDataA = a.get(this.sortKey),
sampleDataB = b.get(this.sortKey);
if (this.reverseSortDirection) {
if (sampleDataA > sampleDataB) { return -1; }
if (sampleDataB > sampleDataA) { return 1; }
return 0;
} else {
if (sampleDataA < sampleDataB) { return -1; }
if (sampleDataB < sampleDataA) { return 1; }
return 0;
}
},
Mit Ausnahme der beiden Modelle von Comparator wird bei Änderungen an der Sammlung oder dem Modell die Kompartimentfunktion ausgeführt und die Reihenfolge der Sammlung geändert.
Ich habe diesen Ansatz mit Numbers and Strings getestet und er scheint perfekt für mich zu funktionieren.
Ich hoffe wirklich, dass diese Antwort helfen kann, da ich viele Male mit diesem Problem zu kämpfen habe und normalerweise eine Problemumgehung verwende.
sortKeyund reverseSortDirectionund Anruf .sort()von einem beliebigen Ansicht , die einen Griff an der Sammlung. Für mich einfacher als andere Antworten mit höheren Stimmen.
Dies kann elegant erfolgen, indem die sortBy-Methode überschrieben wird. Hier ist ein Beispiel
var SortedCollection = Backbone.Collection.extend({
initialize: function () {
// Default sort field and direction
this.sortField = "name";
this.sortDirection = "ASC";
},
setSortField: function (field, direction) {
this.sortField = field;
this.sortDirection = direction;
},
comparator: function (m) {
return m.get(this.sortField);
},
// Overriding sortBy (copied from underscore and just swapping left and right for reverse sort)
sortBy: function (iterator, context) {
var obj = this.models,
direction = this.sortDirection;
return _.pluck(_.map(obj, function (value, index, list) {
return {
value: value,
index: index,
criteria: iterator.call(context, value, index, list)
};
}).sort(function (left, right) {
// swap a and b for reverse sort
var a = direction === "ASC" ? left.criteria : right.criteria,
b = direction === "ASC" ? right.criteria : left.criteria;
if (a !== b) {
if (a > b || a === void 0) return 1;
if (a < b || b === void 0) return -1;
}
return left.index < right.index ? -1 : 1;
}), 'value');
}
});
Sie können es also folgendermaßen verwenden:
var collection = new SortedCollection([
{ name: "Ida", age: 26 },
{ name: "Tim", age: 5 },
{ name: "Rob", age: 55 }
]);
//sort by "age" asc
collection.setSortField("age", "ASC");
collection.sort();
//sort by "age" desc
collection.setSortField("age", "DESC");
collection.sort();
Diese Lösung hängt nicht vom Feldtyp ab.
Hier ist eine wirklich einfache Lösung für diejenigen, die einfach die aktuelle Reihenfolge umdrehen möchten. Dies ist nützlich, wenn Sie eine Tabelle haben, deren Spalten in zwei Richtungen angeordnet werden können.
collection.models = collection.models.reverse()
Sie können es mit so etwas kombinieren, wenn Sie an der Tischhülle (Coffeescript) interessiert sind:
collection.comparator = (model) ->
model.get(sortByType)
collection.sort()
if reverseOrder
collection.models = collection.models.reverse()
Ich hatte eine etwas andere Anforderung, da ich meine Modelle in einer Tabelle anzeigte und sie nach jeder Spalte (Modelleigenschaft) und entweder aufsteigend oder absteigend sortieren wollte.
Es hat eine Menge Zeit gekostet, um alle Fälle zum Laufen zu bringen (wobei Werte Zeichenfolgen, leere Zeichenfolgen, Datumsangaben, Zahlen sein können. Ich denke jedoch, dass dies ziemlich nahe ist.
inverseString: function(str)
{
return str.split("").map(function (letter) { return String.fromCharCode(-(letter.charCodeAt(0))); }).join("");
}
getComparisonValue: function (val, desc)
{
var v = 0;
// Is a string
if (typeof val === "string")
{
// Is an empty string, upgrade to a space to avoid strange ordering
if(val.length === 0)
{
val = " ";
return desc ? this.inverseString(val) : val;
}
// Is a (string) representing a number
v = Number(val);
if (!isNaN(v))
{
return desc ? -1 * v : v;
}
// Is a (string) representing a date
v = Date.parse(val);
if (!isNaN(v))
{
return desc ? -1 * v : v;
}
// Is just a string
return desc ? this.inverseString(val) : val;
}
// Not a string
else
{
return desc ? -1 * val : val;
}
},
verwenden:
comparator: function (item)
{
// Store the collumn to 'sortby' in my global model
var property = app.collections.global.get("sortby");
// Store the direction of the sorting also in the global model
var desc = app.collections.global.get("direction") === "DESC";
// perform a comparison based on property & direction
return this.getComparisonValue(item.get(property), desc);
},
Ich habe gerade die Sortierfunktion überschrieben, um das Modellarray nach Abschluss umzukehren. Außerdem habe ich das Auslösen des Sortierereignisses erst nach Abschluss des Rückwärtsgangs unterbrochen.
sort : function(options){
options = options || {};
Backbone.Collection.prototype.sort.call(this, {silent:true});
this.models.reverse();
if (!options.silent){
this.trigger('sort', this, options);
}
return this;
},
Ich bin kürzlich auf dieses Problem gestoßen und habe gerade beschlossen, eine rsort-Methode hinzuzufügen.
Collection = Backbone.Collection.extend({
comparator:function(a, b){
return a>b;
},
rsort:function(){
var comparator = this.comparator;
this.comparator = function(){
return -comparator.apply(this, arguments);
}
this.sort();
this.comparator = comparator;
}
});
Hoffentlich findet das jemand nützlich
Hier ist eine schnelle und einfache Möglichkeit, die Modelle einer Sammlung mithilfe von UnderscoreJS rückwärts zu sortieren
var reverseCollection = _.sortBy(this.models, function(model) {
return self.indexOf(model) * -1;
});