7

バックボーンで保存できない値を処理する標準的な方法はありますか?

例えば

MyModel = Backbone.extend(Backbone.Model, {
    initialize: function () {
        this.set({'inches': this.get('mm') / 25});
    }
})

このモデルでsave()を呼び出すと、に対応するデータベースフィールドがないため、エラーがスローされますinches。これを修正するいくつかの方法を考えることができますが、これに一般的に最もよく使用される、試行錯誤されたアプローチがあるかどうか疑問に思っていますか?

現時点での私の好ましい解決策は、BackboneのtoJSONメソッドを拡張し、ブールパラメータdontCleanupを渡して、テンプレートへの受け渡しなど、必要なときにすべてのモデルの値(保存できない値を含む)を返すことができるようにすることです。

4

3 に答える 3

11

PeterLyonのアイデアが好きです。私はそれについて何度か考えましたが、実際にそれを実行することはありませんでした。しかし、私がこれを処理したすべての方法について、ここに私の2つのお気に入りがあります。

  • 「属性」以外の値
  • モデルを表示

非属性値

これは単純です。必要な値をモデルの標準属性に保存しないでください。代わりに、オブジェクトに直接アタッチします。


myModel.someValue = "some value";

setここでの大きな問題は、モデルの呼び出しに関連するすべてのイベントを取得できないことです。だから私はこれを私のためにすべてを行う方法でまとめる傾向があります。たとえば、私がモデルに適用する一般的な方法はselect、このモデルが選択されていると言うことです。


MyModel = Backbone.Model.extend({
  select: function(){
    if (!this.selected){
      this.selected = true;
      this.trigger("change:selected", this, this.selected);
    }
  }
});

あなたの場合、これが良いアプローチになるかどうかはわかりません。すでに属性にある値に基づいて計算する必要のあるデータがあります。

そのために、私はビューモデルを使用する傾向があります。

モデルを表示します。

基本的な考え方は、通常どおり、永続化可能なバックボーンモデルを作成することです。しかし、あなたはやって来て、元のモデルを継承し、必要なすべてのデータを追加する別のモデルを作成します。

これを行うには非常に多くの方法があります。非常に単純なバージョンは次のとおりです。


MyModel = Backbone.Model.Extend({ ... });

MyViewModel = function(model){
  var viewModel = Object.create(model);

  viewModel.toJSON = function(){
    var json = model.toJSON();
    json.inches = json.mm / 25;
    return json;
  };

  return viewModel;
});

これをラップすることの大きな利点はObject.create、プロトタイプの継承状況が発生したため、モデルの標準機能がすべてそのまま残っていることです。ビューモデルのメソッドをオーバーライドしただけtoJSONなので、inches属性を持つJSONオブジェクトが返されます。

次に、これを必要とするビューで、モデルを初期化関数でラップします。


MyView = Backbone.View.extend({
  initialize: function(){
    this.model = MyViewModel(this.model);
  },

render: function(){ var data = this.model.toJSON(); // returns with inches } });

必要に応じて呼び出すこともできますnew MyViewModel(this.model)が、関数からオブジェクトインスタンスを明示的に返すため、最終的には何も変わりませんMyViewModel

ビューのrenderメソッドがを呼び出すと、それを使用して属性をtoJSON取得します。inches

もちろん、この実装には潜在的なメモリの問題とパフォーマンスの問題がいくつかありますが、これらはビューモデルのより良いコードで簡単に解決できます。ただし、この迅速で汚い例は、あなたを道に導くはずです。

于 2012-05-06T14:30:37.073 に答える
3

私はこれがそれをするべきだと思います。を有効なスキーマとして定義し、の間に有効なModel defaultsそのサブセットのみを返します。this.attributestoJSON

var Model = Backbone.Model.extend({
  defaults: {
    foo: 42,
    bar: "bar"
  },

  toJSON: function () {
    var schemaKeys = _.keys(this.defaults);
    var allowedAttributes = {};
    _.each(this.attributes, function (value, key) {
    if (_.include(schemaKeys, key)) {
      allowedAttributes[key] = value;
    }
    return allowedAttributes;
  }
});

_.pickアンダースコア1.3.3を使用できるようになると、コードが少し短くなることに注意してください。バックボーンコミュニティを旅する中で「試してテストした」コンベンションを見たことがありません。バックボーンは非常に多くのオプションを開いたままにしているため、コンベンションが出現しない場合がありますが、このスタックオーバーフローの質問が何をもたらすかを見ていきます。

于 2012-05-06T13:48:04.240 に答える
2

特に、計算されたプロパティ、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

値が必要な場合は、変更をリッスンして次setinches値を調整することもできます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は常に「永続的」(または「保存可能」)属性のみを返す必要があります。

于 2013-06-07T13:22:25.283 に答える