2013-03-20 9 views
9

Ho una collezione di Animali.Collezione backbone di modelli polimorfici

App.Collections.Animals extends Backbone.Collection 
    model: App.Animal 
    url: '/animals/' #returns json 

E queste classi di animali:

App.Models.Animal extends Backbone.Model 

App.Models.Monkey extends App.Models.Animal 
    defaults:{type:'Monkey'} 

App.Models.Cat extends App.Models.Animal 
    defaults:{type:'Cat'} 

App.Models.Dog extends App.Models.Animal 
    defaults:{type:'Dog'} 

Quando collezione è piena di JSON (record contengono il tipo di attributo) Voglio modelli per essere istanziati come modelli sub-classificati (Scimmia, Gatto, Cane) e non come animale. Come puoi ottenere questo?

risposta

12

Da Backbone documentation:

Una raccolta può contenere anche modelli polimorfici sovrascrivendo questa proprietà con una funzione che restituisce un modello.

var Library = Backbone.Collection.extend({ 

    model: function(attrs, options) { 
    if (condition) { 
     return new PublicDocument(attrs, options); 
    } else { 
     return new PrivateDocument(attrs, options); 
    } 
    } 

}); 
0

Sovrascrivi _prepareModel della raccolta backbone. La collezione new utilizza sottoclassi quando definite altrimenti utilizza il modello predefinito.

class App.Collections.Animals extends Backbone.Collection 

model: App.Models.Animal 

_prepareModel: (attrs, options) -> 
    if attrs instanceof Backbone.Model 
    attrs.collection = @ 
    return attrs 

    options || (options = {}) 
    options.collection = @ 
    model_class = APP.Models[attrs.ntype] or this.model 
    model = new model_class(attrs, options) 
    if (!model._validate(attrs, options)) 
    false 
    else 
    model 
6

La soluzione è semplice (scusate il JS, non so CoffeeScript):

var SmartZoo = Backbone.Collection.extend({ 
    model: function (attrs, options) { 
     // This code assumes that the object looks something like '{ type: "Cat", ... }'. 
     switch (attrs.type) { 
      case 'Cat': 
       return new Cat(attrs, options); 
      case 'Dog': 
       return new Dog(attrs, options); 
      default: // Unknown subclass 
       return new Animal(attrs, options); 
     } 
    } 
}); 

Dovete:

  1. includere un attributo nel modello da che puoi dedurre dal tipo di modello Backbone da creare. In questo esempio, i miei oggetti contengono un attributo chiamato "tipo" il cui valore è il nome completo del tipo Backbone che lo rappresenta. Assicurarsi di impostarlo nelle impostazioni predefinite o inizializzare il modello in modo da poter aggiungere anche istanze di modelli reali alla raccolta.
  2. Definire la proprietà dei modelli della raccolta come una funzione. Il primo parametro di questa funzione sarà l'oggetto JS non elaborato (se questo è ciò che è stato passato) o l'oggetto attributi di un modello Backbone. Ad ogni modo, puoi accedere al campo tipo come una proprietà di questo oggetto.
  3. Esegui la logica per dedurre il modello corretto dal campo del tipo.
  4. Restituisce un'istanza del modello corretto dalla funzione dei modelli.

Ecco un JSFiddle che mostra questa collezione polimorfica in azione: http://jsfiddle.net/FiddlerOnTheTarmac/uR2Sa/

+0

Basta notare che se la raccolta può avere un sacco di modelli 'if(); altrimenti se; else' è molto più performante di 'switch' – seebiscuit