webentwicklung-frage-antwort-db.com.de

Richtige Methode, um eine Sammlung von backbone.js im Handumdrehen zu sortieren

Ich kann das erfolgreich machen:

App.SomeCollection = Backbone.Collection.extend({
  comparator: function( collection ){
    return( collection.get( 'lastName' ) );
  }
});

Das ist schön, wenn ich eine Sammlung haben möchte, die nur nach 'lastName' sortiert ist. Aber ich muss diese Sortierung dynamisch durchführen lassen. Manchmal muss ich stattdessen beispielsweise nach 'Vorname' sortieren.

Meine völligen Fehler sind:

Ich habe versucht, eine zusätzliche Variable, die die Variable angibt, an sort() weiterzuleiten. Das hat nicht funktioniert. Ich habe auch sortBy() ausprobiert, was auch nicht funktioniert hat. Ich habe versucht, meine eigene Funktion an sort () zu übergeben, aber das hat auch nicht funktioniert. Übergeben einer benutzerdefinierten Funktion an sortBy(), nur damit das Ergebnis nicht über eine each -Methode verfügt, um den Punkt zu umgehen, an dem eine neu sortierte Backbone-Auflistung vorhanden ist.

Kann jemand ein praktisches Beispiel für das Sortieren nach einer Variablen geben, die nicht fest in der Komparatorfunktion programmiert ist? Oder irgendein Hack, den du hast, der funktioniert? Wenn nicht, ein funktionierender sortBy() Aufruf?

42
kikuchiyo

Interessante Frage. Ich würde hier eine Variante des Strategiemusters ausprobieren. Sie können einen Hash mit Sortierfunktionen erstellen und dann comparator basierend auf dem ausgewählten Mitglied des Hashs festlegen:

App.SomeCollection = Backbone.Collection.extend({
    comparator: strategies[selectedStrategy],
    strategies: {
        firstName: function () { /* first name sorting implementation here */ }, 
        lastName: function () { /* last name sorting implementation here */ },
    },
    selectedStrategy: "firstName"
});

Dann können Sie Ihre Sortierstrategie im Handumdrehen ändern, indem Sie den Wert der Eigenschaft selectedStrategy aktualisieren.

EDIT: Nachdem ich ins Bett gegangen war, wurde mir klar, dass dies nicht ganz so funktioniert, wie ich es oben geschrieben habe, da wir ein Objekt-Literal an Collection.extend Übergeben. Die Eigenschaft comparator wird einmalig ausgewertet, wenn das Objekt erstellt wird, sodass sie sich nicht im laufenden Betrieb ändert, es sei denn, Sie werden dazu gezwungen. Es gibt wahrscheinlich eine sauberere Möglichkeit, dies zu tun, aber dies zeigt, wie die Komparatorfunktionen im laufenden Betrieb umgeschaltet werden:

var SomeCollection = Backbone.Collection.extend({
    comparator: function (property) {
        return selectedStrategy.apply(myModel.get(property));
    },
    strategies: {
        firstName: function (person) { return person.get("firstName"); }, 
        lastName: function (person) { return person.get("lastName"); },
    },
    changeSort: function (sortProperty) {
        this.comparator = this.strategies[sortProperty];
    },
    initialize: function () {
        this.changeSort("lastName");
        console.log(this.comparator);
        this.changeSort("firstName");
        console.log(this.comparator);        
    }                                                                                        
});

var myCollection = new SomeCollection;

Hier ist ein jsFiddle , das dies demonstriert.

Die Wurzel all Ihrer Probleme ist, glaube ich, dass Eigenschaften in JavaScript-Objektliteralen sofort ausgewertet werden, wenn das Objekt erstellt wird. Sie müssen die Eigenschaft also überschreiben, wenn Sie sie ändern möchten. Wenn Sie versuchen, eine Art Umschaltung in die Eigenschaft selbst zu schreiben, wird sie auf einen Anfangswert gesetzt und bleibt dort.

Hier ist ein guter Blog-Beitrag , der dies in einem etwas anderen Kontext behandelt.

37
Josh Earl

Wechseln Sie in die Komparatorfunktion, indem Sie ihr eine neue Funktion zuweisen und sortieren.

// Following example above do in the view:

// Assign new comparator
this.collection.comparator = function( model ) {
  return model.get( 'lastname' );
}

// Resort collection
this.collection.sort();

// Sort differently
this.collection.comparator = function( model ) {
  return model.get( 'age' );
}
this.collection.sort();
16
toon.ketels

Das war also meine Lösung, die tatsächlich funktionierte.

  App.Collection = Backbone.Collection.extend({

    model:App.Model,

    initialize: function(){
      this.sortVar = 'firstName';
    },

    comparator: function( collection ){
      var that = this;
      return( collection.get( that.sortVar ) );
    }

  });

Dann in der Ansicht, ich muss M-I-C-K-E-Y M-O-U-S-E es so:

this.collections.sortVar = 'lastVar'

this.collections.sort( this.comparator ).each( function(){
  // All the stuff I want to do with the sorted collection... 
});

Da Josh Earl der einzige war, der überhaupt eine Lösung versuchte und mich in die richtige Richtung führte, akzeptiere ich seine Antwort. Danke Josh :)

12
kikuchiyo

Dies ist eine alte Frage, aber ich hatte kürzlich ein ähnliches Bedürfnis (Sortieren einer Sammlung nach Kriterien, die von einem Benutzer-Klick-Ereignis geliefert werden sollen) und dachte, ich würde meine Lösung für andere teilen, die sich mit diesem Problem befassen. Benötigt kein fest codiertes model.get ('attribute').

Ich habe Dave Newtons Ansatz verwendet, um native JavaScript-Arrays zu erweitern, und es auf Backbone zugeschnitten:

MyCollection = Backbone.Collection.extend({

    // Custom sorting function.
    sortCollection : function(criteria) {

        // Set your comparator function, pass the criteria.
        this.comparator = this.criteriaComparator(criteria);
        this.sort();
    },

    criteriaComparator : function(criteria, overloadParam) {

        return function(a, b) {
            var aSortVal = a.get(criteria);
            var bSortVal = b.get(criteria);

            // Whatever your sorting criteria.
            if (aSortVal < bSortVal) {
                return -1;
            }

            if (aSortVal > bSortVal) {
                return 1;
            }

            else {
                return 0;
            }

        };
    } 

});

Beachten Sie das "overloadParam". Gemäß Dokumentation verwendet Backbone das "sortBy" von Unterstrich, wenn Ihre Komparatorfunktion einen einzelnen Parameter hat, und eine native Sortierung im JS-Stil, wenn sie zwei Parameter hat. Wir brauchen letzteres, daher das "overloadParam".

4
Mark McKelvy

Wenn man sich Quellcode ansieht, scheint es eine einfache Möglichkeit zu geben, den Komparator auf string anstatt auf function zu setzen. Dies funktioniert mit Backbone.Collection mycollection:

        mycollection.comparator = key;
        mycollection.sort();
3
NoBugs

Das habe ich letztendlich für die App gemacht, an der ich gerade arbeite. In meiner Sammlung habe ich:

comparator: function(model) {
    var methodName = applicationStateModel.get("comparatorMethod"),
        method = this[methodName];
    if (typeof(method === "function")) {
        return method.call(null, model);
    }
}

Jetzt kann ich meiner Sammlung einige verschiedene Methoden hinzufügen: fooSort (), barSort () und bazSort ().
Ich möchte, dass fooSort die Standardeinstellung ist, also habe ich das in meinem Zustandsmodell so eingestellt:

var ApplicationState = Backbone.Model.extend({
    defaults: {              
        comparatorMethod: "fooSort"
    }
});

Jetzt muss ich in meiner Ansicht nur noch eine Funktion schreiben, die den Wert von "comparatorMethod" aktualisiert, je nachdem, auf was der Benutzer klickt. Ich habe die Sammlung so eingestellt, dass diese Änderungen abgehört und sortiert werden (), und ich habe die Ansicht so eingestellt, dass sie auf Sortierereignisse wartet und gerendert wird ().

BAZINGA !!!!

0
Neil Girardi