下記のようなJSONをCollectionにsetして配列要素からモデルをつくりたい。
ただそれぞれBackbone.Modelを拡張したxxxModelというモデルで生成したい。
[
{"name":"nekoModel"},
{"name":"inuModel"},
{"name":"usagiModel"}
]
こんな要件があったのでやってみた。要素のなかに生成したいclass名を定義しておく。
[
{"name":"nekoModel", "class":"NekoModel"},
{"name":"inuModel", "class":"InuModel"},
{"name":"usagiModel", "class":"UsagiModel"}
]
新案
modelを関数にしたらもっとスマートに対応できると指摘頂きました。ありがとうございます。
これをうけての新案です。sampleではコンストラクタを書いてその中でmodel型を状況に応じて変更するようにしていました。
これでも十分対応可能なのですが、typescriptだとあつかいずらいので別classとして定義します。
modelプロパティにattrsからmodelのclass名を取得して返すModelSelectorを指定します。
(function (Backbone) {
Backbone.ModelSelector = Backbone.Model.extend(
constructor(attrs, options){
var modelClass;
Backbone.Model.apply(this, arguments);
modelClass =this.get("class");
return modelClass;
}
);
}(Backbone));
var Library = Backbone.Collection.extend({
model: ModelSelector
});
やっていることは旧案と同じですが、強引なオーバライドをしてない、
collection毎にオーバライドするか否かを選択できるようになったので
扱いづらくなったと思います。
旧案
attrにclassが定義されていればそのclassでnewするようにオーバライド。
(function (Backbone) {
_.extend(Backbone.Collection.prototype, {
_prepareModel: function (attrs, options) {
if (attrs instanceof Backbone.Model) {
if (!attrs.collection) attrs.collection = this;
return attrs;
}
options || (options = {});
options.collection = this;
var model;
var myClass = attrs["class"];
if (myClass) {
model = new myClass(attrs, options);
}else{
model = new this.model(attrs, options);
}
if (!model._validate(attrs, options)) {
this.trigger('invalid', this, attrs, options);
return false;
}
return model;
}
});
}(Backbone));
ただそんなに必要になるケースはないと思う・・