json - template - backbonejs github
Una colección de Backbone.js de múltiples subclases de modelos (5)
Tengo una API REST Json que devuelve una lista de "libros de registro". Existen muchos tipos de registros que implementan comportamientos diferentes pero similares. La implementación del lado del servidor en la capa Base de datos es una especie de herencia de tabla única, por lo que cada representación JSON de un libro de registro contiene su "tipo":
[
{"type": "ULM", "name": "My uml logbook", ... , specific_uml_logbook_attr: ...},
{"type": "Plane", "name": "My plane logbook", ... , specific_plane_logbook_attr: ...}
]
Me gustaría replicar este modelo de servidor en el lado del cliente, así que tengo una clase básica de Logbook
y múltiples subclases de logbook:
class Logbook extends Backbone.Model
class UmlLogbook extends Logbook
class PlaneLogbook extends Logbook
...
My Backbone.Collection
es un conjunto de modelos de Logbook
que uso para consultar la API de JSON:
class LogbookCollection extends Backbone.Collection
model: Logbook
url: "/api/logbooks"
Cuando busco la colección del libro de registro, ¿hay alguna manera de convertir cada libro de registro a su subclase correspondiente (según el atributo "tipo" de JSON)?
De hecho hay
Cuando llamas ''fetch'' a una colección, pasa la respuesta a través de Backbone.Collection.parse antes de agregarlo a la colección.
La implementación predeterminada de ''parse'' solo pasa la respuesta como está, pero puede anularla para devolver una lista de modelos que se agregarán a la colección:
class Logbooks extends Backbone.Collection
model: Logbook
url: ''api/logbooks''
parse: (resp, xhr) ->
_(resp).map (attrs) ->
switch attrs.type
when ''UML'' then new UmlLogbook attrs
when ''Plane'' then new PLaneLogbook attrs
EDITAR: whoa, idbentley llegó antes que yo. la única diferencia es que usó ''cada'' y yo usé ''mapa''. Ambos funcionarán, pero de manera diferente.
El uso de ''cada'' rompe efectivamente la cadena que inició la llamada ''búsqueda'' (al devolver ''indefinido'' - la subsecuente llamada a ''reiniciar'' (o ''agregar'') por lo tanto no hará nada) y hace todo el procesamiento allí en el análisis función.
El uso de ''mapa'' simplemente transforma la lista de atributos en una lista de modelos y la pasa nuevamente a la cadena que ya está en movimiento.
Diferentes golpes.
EDITAR DE NUEVO: acaba de darse cuenta de que también hay otra forma de hacer esto:
El atributo ''modelo'' en una colección está allí solo para que la colección sepa cómo crear un nuevo modelo si se le pasan atributos en ''agregar'', ''crear'' o ''restablecer''. Entonces podrías hacer algo como:
class Logbooks extends Backbone.Collection
model: (attrs, options) ->
switch attrs.type
when ''UML'' then new UmlLogbook attrs, options
when ''Plane'' then new PLaneLogbook attrs, options
# should probably add an ''else'' here so there''s a default if,
# say, no attrs are provided to a Logbooks.create call
url: ''api/logbooks''
La ventaja de esto es que la colección ahora sabrá cómo "lanzar" la subclase correcta de Logbook para operaciones que no sean ''fetch''.
Sí. Puede anular la función de parse
en la colección (voy a utilizar javascript en lugar de coffeescript, porque es lo que sé, pero la asignación debe ser fácil):
LogbookCollection = Backbone.Collection.extend({
model: Logbook,
url: "/api/logbooks",
parse: function(response){
var self = this;
_.each(response, function(logbook){
switch(logbook.type){
case "ULM":
self.add(new UmlLogBook(logbook);
break;
case "Plane":
...
}
}
}
});
Espero que esto ayude.
Tal vez es malo usar eval, pero esto es mucho más estilo ruby way (coffeescript):
parse: (resp)->
_(resp).map (attrs) ->
eval("new App.Models.#{attrs.type}(attrs)")
Por lo tanto, no necesita escribir muchos conmutadores / mayúsculas, simplemente configure el atributo de tipo en su JSON. Funciona muy bien con rails + citier u otra solución de herencia multitable. Puede agregar nuevos descendientes sin agregarlos a sus casos.
Y puede usar tales construcciones en otros lugares donde necesite muchos conmutadores / cajas dependiendo de su clase de modelo.
a partir de la red troncal 0.9.1, comencé a usar el método descrito en la solicitud de extracción de esa-matti suuronen:
https://github.com/documentcloud/backbone/pull/1148
después de aplicar el parche, su colección sería algo como esto:
LogbookCollection = Backbone.Collection.extend({
model: Logbook,
createModel: function (attrs, options) {
if (attrs.type === "UML") { // i''am assuming ULM was a typo
return new UmlLogbook(attrs, options);
} else if (attrs.type === "Plane") {
return new Plane(attrs, options);
} else {
return new Logbook(attrs, options);
// or throw an error on an unrecognized type
// throw new Error("Bad type: " + attrs.type);
}
}
});
creo que esto cabría ya que estás usando STI (todos los modelos tienen identificadores únicos)
parse
puede funcionar solo, o puede usar la característica submodelTypes de Backbone-Relational .