私はそれができることをよく知っており、かなりの数の場所を見ました( コレクション全体を保存するためのベストプラクティス? )。しかし、「正確にどのように」コードで書かれているのかまだわかりません。 (投稿では英語で説明しています。javascript固有の説明があればいいのですが:)
モデルのコレクションがあるとします-モデル自体にネストされたコレクションがある場合があります。親コレクションのtoJSON()メソッドをオーバーライドし、有効なJSONオブジェクトを取得しています。コレクション全体(対応するJSON)を「保存」したいのですが、バックボーンにはその機能が組み込まれていないようです。
var MyCollection = Backbone.Collection.extend({
model:MyModel,
//something to save?
save: function() {
//what to write here?
}
});
あなたが言わなければならないどこかを知っています:
Backbone.sync = function(method, model, options){
/*
* What goes in here?? If at all anything needs to be done?
* Where to declare this in the program? And how is it called?
*/
}
処理で「ビュー」が完了すると、サーバーに自身を「保存」するようにコレクションに指示する責任があります(一括更新/作成リクエストを処理できます)。
発生する質問:
それが本当にトリッキーな仕事であれば、ビュー内でjQuery.ajaxを呼び出してthis.successMethod
またはthis.errorMethod
成功/エラーコールバックとして??機能しますか?
バックボーンの考え方と同期する必要があります-コレクション全体の同期など、何かが欠けていることは間違いありません。
私の当面の考えは、Backbone.Collectionのsaveメソッドのメソッドをオーバーライドするのではなく、コレクションを別のBackbone.Modelでラップし、そのtoJSONメソッドをオーバーライドすることです。そうすると、Backbone.jsはモデルを単一のリソースとして扱い、backoneが過度に考える方法をハックする必要はありません。
Backbone.CollectionにはtoJSONメソッドがあるため、ほとんどの作業は自動的に行われます。ラッパーBackbone.ModelのtoJSONメソッドをBackbone.collectionにプロキシするだけです。
var MyCollectionWrapper = Backbone.Model.extend({
url: "/bulkupload",
//something to save?
toJSON: function() {
return this.model.toJSON(); // where model is the collection class YOU defined above
}
});
非常にシンプルな...
Backbone.Collection.prototype.save = function (options) {
Backbone.sync("create", this, options);
};
...コレクションに保存方法を提供します。これは、何が変更されたかに関係なく、常にすべてのコレクションのモデルをサーバーにポストすることに注意してください。オプションは、通常のjQuery ajaxオプションです。
最終的に、「保存」のようなメソッドを持ち、その中に$ .ajaxを呼び出しました。 @brandgonesurfingが示唆するようにラッパークラスを追加する必要なく、それをより詳細に制御できました(ただし、私はこのアイデアを絶対に気に入っていますが): ajax呼び出しで...
これがつまずく人を助けることを願っています...
これは、クライアントとサーバーとの間の契約内容によって異なります。以下は、_/parent/:parent_id/children
_を使用した_{"children":[{child1},{child2}]}
_へのPUTが親の子をPUTにあるものに置き換え、_{"children":[{child1},{child2}]}
_を返す簡単なCoffeeScriptの例です。
_class ChildElementCollection extends Backbone.Collection
model: Backbone.Model
initialize: ->
@bind 'add', (model) -> model.set('parent_id', @parent.id)
url: -> "#{@parent.url()}/children" # let's say that @parent.url() == '/parent/1'
save: ->
response = Backbone.sync('update', @, url: @url(), contentType: 'application/json', data: JSON.stringify(children: @toJSON()))
response.done (models) => @reset models.children
return response
_
これは非常に単純な例です。もっと多くのことができます... save()が実行されるときのデータの状態、サーバーに出荷するために必要な状態、およびサーバーが提供するものに依存します。バック。
サーバーが_[{child1},{child2]
_のPUTで問題ない場合、Backbone.sync行はresponse = Backbone.sync('update', @toJSON(), url: @url(), contentType: 'application/json')
に変更できます。
答えは、サーバー側でコレクションをどのように処理するかによって異なります。
投稿に追加データを送信する必要がある場合、ラッパーモデルまたはリレーショナルモデルが必要になる場合があります。
wrapper modelでは、常に独自のparseメソッドを記述する必要があります:
var Occupants = Backbone.Collection.extend({
model: Person
});
var House = Backbone.Model.extend({
url: function (){
return "/house/"+this.id;
},
parse: function(response){
response.occupants = new Occupants(response.occupants)
return response;
}
});
リレーショナルモデルのほうが良いと思います。なぜなら、簡単に設定できるからですそして、あなたは includeInJSON オプションで規制することができます。休息サービス。
var House = Backbone.RelationalModel.extend({
url: function (){
return "/house/"+this.id;
},
relations: [
{
type: Backbone.HasMany,
key: 'occupants',
relatedModel: Person,
includeInJSON: ["id"],
reverseRelation: {
key: 'livesIn'
}
}
]
});
追加のデータを送信しない場合、コレクション自体を同期することができます。その場合、コレクション(またはコレクションプロトタイプ)にsaveメソッドを追加する必要があります。
var Occupants = Backbone.Collection.extend({
url: "/concrete-house/occupants",
model: Person,
save: function (options) {
this.sync("update", this, options);
}
});
私が知っている古いスレッド、私がやったことは次のとおりです:
Backbone.Collection.prototype.save = function (options) {
// create a tmp collection, with the changed models, and the url
var tmpCollection = new Backbone.Collection( this.changed() );
tmpCollection.url = this.url;
// sync
Backbone.sync("create", tmpCollection, options);
};
Backbone.Collection.prototype.changed = function (options) {
// return only the changed models.
return this.models.filter( function(m){
return m.hasChanged()
});
};
// and sync the diffs.
self.userCollection.save();
かなり緊張します:)
また、Backboneコレクションには組み込みの保存機能がないことに驚きました。これを行うためにバックボーンコレクションに配置したものを次に示します。コレクション内の各モデルを繰り返し処理して、個別に保存することは絶対に避けたいです。また、Nodeを使用してバックエンドでBackboneを使用しているため、ネイティブBackbone.sync
私の小さなプロジェクトでフラットファイルに保存します。ただし、コードはほとんど同じである必要があります。
save: function(){
Backbone.sync('save', this, {
success: function(){
console.log('users saved!');
}
});
}
以下に簡単な例を示します。
var Books = Backbone.Collection.extend({
model: Book,
url: function() {
return '/books/';
},
save: function(){
Backbone.sync('create', this, {
success: function() {
console.log('Saved!');
}
});
}
});
コレクションでsave()メソッドを呼び出すと、定義されたURLにPUTメソッドリクエストが送信されます。
私は次のようなものを試してみます:
var CollectionSync = function(method, model, [options]) {
// do similar things to Backbone.sync
}
var MyCollection = Backbone.Collection.extend({
sync: CollectionSync,
model: MyModel,
getChanged: function() {
// return a list of models that have changed by checking hasChanged()
},
save: function(attributes, options) {
// do similar things as Model.save
}
});
受け入れられた答えはかなり良いですが、さらに一歩進んで、リスナーに適切なイベントが発生することを保証するコードを提供すると同時に、オプションのajaxイベントコールバックを渡すこともできます:
save: function( options ) {
var self = this;
var success = options.success;
var error = options.error;
var complete = options.complete;
options.success = function( response, status, xhr ) {
self.trigger('sync', self, response, options);
if (success) return success.apply(this, arguments);
};
options.error = function( response, status, xhr ) {
self.trigger('error', self, response, options);
if (error) return error.apply(this, arguments);
};
options.complete = function( response, status, xhr ) {
if (complete) return complete.apply(this, arguments);
}
Backbone.sync('create', this, options);
}
2017年にまだbackbone.jsを使用している人にとって、受け入れられた答えは機能していません。
ラッパーモデルでtoJSON()オーバーライドを削除し、モデルラッパーをインスタンス化するときにコレクションでtoJSONを呼び出してみてください。
new ModelWrapper(Collection.toJSON());