可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a collection of Animals.
App.Collections.Animals extends Backbone.Collection model: App.Animal url: '/animals/' #returns json
And these animal classes:
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'}
When collection is filled with JSON (records contain the type attribute) I want models to be instantiated as sub-classed models (Monkey,Cat,Dog) and not as Animal. How can you achieve this?
回答1:
From Backbone documentation:
A collection can also contain polymorphic models by overriding this property with a function that returns a model.
var Library = Backbone.Collection.extend({ model: function(attrs, options) { if (condition) { return new PublicDocument(attrs, options); } else { return new PrivateDocument(attrs, options); } } });
回答2:
The solution is straightforward (pardon the JS, I don't know 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); } } });
You have to:
- Include an attribute in your model from which you can infer the type of Backbone model to create. In this example, my objects contain an attribute called "type" whose value is the full name of the Backbone type that represents it. Be sure to set it in the defaults or initialize of your Model so that you can also add real model instances to the collection.
- Define the models property of your collection as a function. The first parameter to this function will be the raw JS object (if that's what you passed in), or the attributes object of a Backbone model. Either way, you can access your type field as a property of this object.
- Execute your logic to infer the proper model from your type field.
- Return an instance of the correct model from the models function.
Here is a JSFiddle that shows this polymorphic collection in action: http://jsfiddle.net/FiddlerOnTheTarmac/uR2Sa/
回答3:
Override backbone collection's _prepareModel. The collection new uses subclasses when defined otherwise uses the default model.
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