これを処理するためのいくつかのメソッドで Backbone.Collection を拡張することになりました。
saveChangeMethod は、Backbone.sync に渡されるダミー モデルを作成します。モデルからバックボーンの同期メソッドが必要とするのは、その url プロパティと toJSON メソッドだけなので、これを簡単にノックアップできます。
内部的には、モデルの toJSON メソッドはその属性のコピー (サーバーに送信される) のみを返すため、モデルの配列を返すだけの toJSON メソッドを喜んで使用できます。Backbone.sync はこれを文字列化して、属性データだけを提供します。
成功すると、saveChanged はコレクションでイベントを発生させ、1 回処理します。バッチのモデルのいずれかで変更された属性ごとに、特定のイベントを 1 回発生させるコードを少し追加しました。
Backbone.Collection.prototype.saveChanged = function () {
var me = this,
changed = me.getChanged(),
dummy = {
url: this.url,
toJSON: function () {
return changed.models;
}
},
options = {
success: function (model, resp, xhr) {
for (var i = 0; i < changed.models.length; i++) {
changed.models[i].chnageSilently();
}
for (var attr in changed.attributes) {
me.trigger("batchchange:" + attr);
}
me.trigger("batchsync", changed);
}
};
return Backbone.sync("update", dummy, options);
}
次に必要なのは、コレクションの getChanged() メソッドだけです。これは、変更されたモデルの配列と、変更された属性にフラグを付けるオブジェクトの 2 つのプロパティを持つオブジェクトを返します。
Backbone.Collection.prototype.getChanged = function () {
var models = [],
changedAttributes = {};
for (var i = 0; i < this.models.length; i++) {
if (this.models[i].hasChanged()) {
_.extend(changedAttributes, this.models[i].changedAttributes());
models.push(this.models[i]);
}
}
return models.length ? {models: models, attributes: changedAttributes} : null;
}
これは、バックボーンの「変更されたモデル」パラダイムの使用目的のわずかな悪用ですが、バッチ処理の要点は、モデルが変更されたときに何も起こらないようにする (つまり、イベントが発生しないようにする) ことです。
したがって、{silent: true} をモデルの set() メソッドに渡す必要があるため、バックボーンの hasChanged() を使用して保存待ちのモデルにフラグを立てるのが理にかなっています。もちろん、他の目的でモデルを黙って変更していた場合、これは問題になります。collection.saveChanged() はこれらも保存するため、別のフラグを設定することを検討する価値があります。
いずれにせよ、この方法で保存する場合、バックボーンがモデルが変更されていないと (変更イベントをトリガーせずに) 認識していることを確認する必要があるため、モデルが変更されていないかのように手動で操作する必要があります。変更されました。saveChanged() メソッドは、変更されたモデルを繰り返し処理し、モデルでこの changeSilently() メソッドを呼び出します。これは基本的に、トリガーのない Backbone の model.change() メソッドです。
Backbone.Model.prototype.changeSilently = function () {
var options = {},
changing = this._changing;
this._changing = true;
for (var attr in this._silent) this._pending[attr] = true;
this._silent = {};
if (changing) return this;
while (!_.isEmpty(this._pending)) {
this._pending = {};
for (var attr in this.changed) {
if (this._pending[attr] || this._silent[attr]) continue;
delete this.changed[attr];
}
this._previousAttributes = _.clone(this.attributes);
}
this._changing = false;
return this;
}
使用法:
model1.set({key: value}, {silent: true});
model2.set({key: value}, {silent: true});
model3.set({key: value}, {silent: true});
collection.saveChanged();
RE。RESTfulness.. コレクションのエンドポイントに PUT を実行して、レコードの「一部」を変更するのは適切ではありません。技術的には、PUT はコレクション全体を置き換える必要がありますが、アプリケーションで実際にコレクション全体を置き換える必要が生じるまでは、実用的なアプローチを喜んで採用します。