2012-04-17 15 views
15

He visto algunas maneras diferentes de obtener el modelo siguiente o anterior de una colección, pero me preguntaba si alguien podría ofrecerme algún consejo sobre la forma en que decidí implementarlo. Mi colección está ordenada, pero la identificación que estoy ordenando no garantiza que sea secuencial. Solo se garantiza que es único. Supongamos que los ID más pequeños son entradas "más antiguas" para la colección y los ID más grandes son "más nuevos".Obteniendo el modelo siguiente y anterior de una colección

MyCollection = Backbone.Collection.extend({ 
    model: MyModel, 
    initialize:function(){ 
    this.getElement = this._getElement(0); 
    }, 
    comparator: function(model) { 
    return model.get("id"); 
    }, 
    _getElement: function (index){ 
    var self = this; 
    return function (what){ 
    if (what === "next"){ 
     if (index+1 >= self.length) return null; 
     return self.at(++index); 
    } 
    if (what === "prev"){ 
     if (index-1 < 0) return null; 
     return self.at(--index); 
    } 
    // what doesn't equal anything useful 
    return null; 
    }; 
    } 
}); 

Al utilizar getElement, hago cosas como getElement ("siguiente") y getElement ("Anterior") para pedir el modelo anterior o siguiente en mi colección. Lo que se devuelve de getElement es el modelo real, no el índice. Conozco collection.indexOf, pero quería una forma de recorrer una colección sin tener primero un modelo para empezar. ¿Es esta implementación más difícil de lo que necesita ser?

Respuesta

23

Haría algo como esto. Tenga en cuenta que no hay ningún error en el manejo actualmente, por lo tanto, si actualmente se encuentra en el primer modelo de la colección e intenta obtener el anterior, probablemente obtendrá un error.

MyCollection = Backbone.Collection.extend({ 
    model: MyModel, 
    initialize:function(){ 
    this.bindAll(this); 
    this.setElement(this.at(0)); 
    }, 
    comparator: function(model) { 
    return model.get("id"); 
    }, 
    getElement: function() { 
    return this.currentElement; 
    }, 
    setElement: function(model) { 
    this.currentElement = model; 
    }, 
    next: function(){ 
    this.setElement(this.at(this.indexOf(this.getElement()) + 1)); 
    return this; 
    }, 
    prev: function() { 
    this.setElement(this.at(this.indexOf(this.getElement()) - 1)); 
    return this; 
    } 
}); 

Para avanzar al siguiente modelo collection.next(). Para pasar al siguiente modelo y devolverlo var m = collection.next().getElement();

Para explicar un poco mejor cómo funciona next/prev.

// The current model 
this.getElement(); 
// Index of the current model in the collection 
this.indexOf(this.getElement()) 
// Get the model either one before or one after where the current model is in the collection 
this.at(this.indexOf(this.getElement()) + 1) 
// Set the new model as the current model 
this.setElement(this.at(this.indexOf(this.getElement()) + 1)); 
+0

me gustan algunas de sus ideas, especialmente al usar this.at() en el método de inicialización. Sin embargo, su código es bastante extenso. Si nadie más sugiere algo mejor y/o más conciso, obtendrá la verificación verde :-) Mi método es más corto y evita caerse al final de la colección devolviendo nulo cuando llegue a cualquiera de los extremos. –

+0

Puede acortarlo abandonando las funciones 'set/getElement' y simplemente accediendo directamente al valor' currentElement'. – abraham

+4

Si usa v0.9 +, necesitará tener this.setElement (this.at (0)); eso está actualmente en la función de inicialización llamada después de crear la colección. Esto se debe a que se llama a initialize antes de que Collection cree los modelos. por ejemplo, var myCollection = new MyCollection (data); myCollection.setElement (this.at (0)); –

6

He hecho esto de forma ligeramente diferente porque estoy agregando los métodos al modelo en lugar de a la colección. De esa forma, puedo agarrar cualquier modelo y obtener el siguiente en la secuencia.

next: function() { 
    if (this.collection) { 
     return this.collection.at(this.collection.indexOf(this) + 1); 
    } 
}, 
prev: function() { 
    if (this.collection) { 
     return this.collection.at(this.collection.indexOf(this) - 1); 
    } 
}, 
+0

Aunque me gusta el enfoque, hay algunos problemas con esto en la práctica. 1. Necesita agregar una propiedad de "colección" personalizada a su modelo que haga referencia a la colección específica con la que desea trabajar. Esto supone que su modelo solo es miembro de una sola colección, lo que puede no ser el caso. La arquitectura de Backbone mantiene el modelo "en la oscuridad", por así decirlo, sobre las colecciones y vistas que lo miran para garantizar un acoplamiento flexible y flexibilidad. 2. Estos métodos arrojarán errores si this.collection.indexOf (this) <= 0 || this.collection.indexOf (this)> = collection.size(). – 1nfiniti

+0

@mikeyUX Estoy de acuerdo en que solo poder pertenecer a una sola colección puede ser restrictivo, esa es la forma Backbone. Personalmente creo que debería haber alguna implementación de lista en Backbone que se use simplemente para las 'colecciones' de Model, pero sin todas las cosas del lado del servidor, por lo que puedes hacer cosas como múltiples colecciones más fácilmente. Además, podría cambiar esto fácilmente así que es un método en la colección que toma un modelo como argumento: '' 'collection.next (modelo);' '' Finalmente, esto no causa errores en el escenarios sugeridos: devuelve indefinido, ¡lo que se espera! – Tom

2

Chocar este hilo de edad con una solución algo más genérico:

cosas que añadir a Collection.prototype

current: null, 

initialize: function(){ 
    this.setCurrent(0); 
    // whatever else you want to do here... 
}, 

setCurrent: function(index){ 
    // ensure the requested index exists 
    if (index > -1 && index < this.size()) 
     this.current = this.at(index); 
    else 
     // handle error... 
}, 

// unnecessary, but if you want sugar... 
prev: function() { 
    this.setCurrent(this.at(this.current) -1); 
}, 
next: function() { 
    this.setCurrent(this.at(this.current) +1); 
} 

a continuación, puede utilizar los métodos de azúcar para obtener el anterior/próximo modelo como tal ...

collection.prev(); 
collection.next(); 
0

Mi Backbo ne Clase SelectableCollection:

Backbone.Collection.extend({ 
    selectNext: function() { 
     if(this.cursor < this.length - 1) { 
      this.cursor++; 
      this.selected = this.at(this.cursor); 
      this.trigger('selected', this.selected); 
     } 
    }, 

    selectPrevious: function() { 
     if(this.cursor > 0) { 
      this.cursor--; 
      this.selected = this.at(this.cursor); 
      this.trigger('selected', this.selected); 
     } 
    }, 
    selectById: function (id) { 
     this.selected = this.get(id); 
     this.cursor = this.indexOf(this.selected); 
     this.trigger('selected', this.selected); 
    }, 
    unselect: function() { 
     this.cursor = null; 
     this.selected = null; 
     this.trigger('selected', null); 
    } 
}); 
Cuestiones relacionadas