42 votes

La bonne façon de régler un backbone.js de la collecte à la volée

Je peux réussir à faire ceci:

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

Ce qui est agréable si je veux avoir une collection qui n'est triée par 'lastName'. Mais j'ai besoin d'avoir ce tri fait de façon dynamique. Parfois, je vais avoir besoin de trier par, disons, "prenom" à la place.

Ma grande échecs comprennent:

J'ai essayé de passer une variable supplémentaire spécifiant la variable sort() sur. Qui n'a pas fonctionné. J'ai aussi essayé d' sortBy(), ce qui n'a pas fonctionné non plus. J'ai essayé de passer le reste de ma propre fonction pour trier(), mais cela ne fonctionne pas non plus. Passage d'une fonction définie par l'utilisateur sortBy() seulement d'avoir le résultat de ne pas avoir un each méthode, en battant le point d'avoir un nouveau triés épine dorsale de la collection.

Quelqu'un peut-il donner un exemple concret de tri par une variable qui n'est pas codée en dur dans le comparateur de fonction? Ou tout hack vous avez qui fonctionne? Si non, d'un travail, sortBy() appel?

37voto

Josh Earl Points 6462

Question intéressante. Je voudrais essayer une variante sur le modèle de stratégie ici. Vous pouvez créer une table de hachage de fonctions de tri, puis définissez comparator fondée sur les membres de la table de hachage:

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

Ensuite vous pouvez changer votre stratégie de tri à la volée par la mise à jour de la valeur de l' selectedStrategy de la propriété.

EDIT: j'ai réalisé après que je suis allé au lit :) que ce ne serait pas tout à fait comme je l'ai écrit ci-dessus, parce que nous sommes de passage d'un objet littéral Collection.extend. L' comparator de la propriété sera évaluée une fois, lorsque l'objet est créé, afin de ne pas modifier à la volée moins d'y être forcé à le faire. Il est probablement le moyen le plus propre pour ce faire, mais cela démontre la commutation de la comparaison des fonctions à la volée:

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;

Voici un jsFiddle que le démontre.

La racine de l'ensemble de vos problèmes, je pense, est que les propriétés sur l'objet JavaScript littéraux sont évalués immédiatement lorsque l'objet est créé, de sorte que vous devez remplacer la propriété si vous souhaitez le modifier. Si vous essayez d'écrire une sorte de commutation dans la propriété elle-même elle peut être définie à une valeur initiale et d'y rester.

Voici un bon blog qui parle de cela dans un contexte légèrement différent.

17voto

toon.ketels Points 101

Changement comparateur de fonction par l'attribution d'une nouvelle fonction et appeler de tri.

// 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();

13voto

kikuchiyo Points 1408

Alors, c'était ma solution qui fonctionne.

  App.Collection = Backbone.Collection.extend({

    model:App.Model,

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

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

  });

Puis dans la vue, j'ai à M-I-C-K-E-e M-O-Us-E comme ceci:

this.collections.sortVar = 'lastVar'

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

Depuis Josh Earl a été le seul à même de tenter une solution et il ne me diriger dans la bonne direction, j'accepte sa réponse. Merci Josh :)

4voto

Mark McKelvy Points 21

C'est une vieille question, mais j'ai récemment eu un besoin similaire (tri d'une collection basée sur les critères devant être fourni par un utilisateur, cliquez sur l'événement) et j'ai pensé partager ma solution pour d'autres, la lutte contre ce problème. Nécessite pas codé en dur de modèle.get ("attribut").

J'ai essentiellement utilisé Dave Newton approche de l'extension de JavaScript natif de tableaux, et bien adaptée à la colonne vertébrale:

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;
            }

        };
    } 

});

Notez le "overloadParam". Par la documentation, de la colonne vertébrale utilise le trait de Soulignement de "sortBy" si votre comparateur de fonction a un seul param, et un natif JS-style de sorte que si elle dispose de deux paramètres. Nous avons besoin de celui-ci, d'où le "overloadParam".

3voto

NoBugs Points 2258

En regardant le code source, il semble qu'il ya un moyen simple de le faire, réglage de comparaison de chaîne de caractères au lieu de la fonction. Cela fonctionne, compte tenu de la colonne vertébrale.Collection mycollection:

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

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