特に、計算されたプロパティ、ember-data属性、またはコントローラーを介してさまざまな状況を処理するember / ember-dataを使い始めて以来、Backbone.jsで非永続属性を処理することに頭を悩ませてきました。
多くのソリューションは、メソッドをカスタマイズすることを提案していtoJSONます。ただし、一部の一般的なBackboneプラグイン(特にネストされたモデルを処理するプラグイン)は、独自のtoJSONメソッドを実装し、を呼び出してBackbone.Model.prototype.toJSONモデルの属性のオブジェクト表現を取得します。したがってtoJSON、モデル定義のメソッドを上書きすると、これらのプラグインのいくつかの(潜在的に重要な)機能が失われます。
私が思いついた最善の方法は、モデル定義にキーの配列を含め、メソッド自体excludeFromJSONを上書きすることです。toJSONBackbone.Model.prototype
Backbone.Model.prototype.toJSON = function() {
var json = _.clone(this.attributes),
excludeFromJSON = this.excludeFromJSON;
if(excludeFromJSON) {
_.each(excludeFromJSON, function(key) {
delete json[key];
});
}
return json;
};
MyModel = Backbone.Model.extend({
excludeFromJSON: [
'inches'
]
});
このように、非永続キーを定義するだけで済みます(定義するのを忘れた場合、サーバーがエラーをスローしたときにすぐに通知されます!)。プロパティが存在toJSONしない場合、通常どおりに動作します。excludeFromJSON
あなたの場合、inchesはから派生した計算されたプロパティであるmmため、これをモデルのメソッドとして実装することは理にかなっています(mmが変更されたときにインチの値が正しいことを確認します)。
MyModel = Backbone.Model.extend({
inches: function() {
return this.get('mm') / 25;
}
});
ただし、これには、他のすべての属性とは異なる方法でアクセスされるという欠点があります。理想的には、他の属性へのアクセスと一貫性を保つ必要があります。これは、デフォルトの方法を拡張するgetことで実現できます。
var getMixin = {
get: function(attr) {
if(typeof this[attr] == 'function') {
return this[attr]();
}
return Backbone.Model.prototype.get.call(this, attr);
}
};
MyModel = Backbone.Model.extend({
inches: function() {
return this.get('mm') / 25;
}
});
_.extend(MyModel.prototype, getMixin);
これにより、次のことが可能になります。
new MyModel().get('inches');
このアプローチは、基になるattributesハッシュには影響しません。つまり、後で値を指定しない限り、表現にinchesは表示されません。この場合、配列のようなものが必要になります。toJSONsetinchesexcludeFromJSON
値が必要な場合は、変更をリッスンして次setのinches値を調整することもできますmm。
MyModel = Backbone.Model.extend({
initialize: function() {
this.on('change:inches', this.changeInches, this);
},
inches: function() {
return this.get('mm') / 25;
},
changeInches: function() {
this.set('mm', this.attributes.inches * 25);
}
});
_.extend(MyModel.prototype, getMixin);
JSBinの完全な例を参照してください。
このメソッドの(公式?)目的がtoJSON、サーバーと同期するためのモデルを準備することとして最近再定義されたことも注目に値します。このため、呼び出しtoJSONは常に「永続的」(または「保存可能」)属性のみを返す必要があります。