web-dev-qa-db-ja.com

Backbone.js-Backbone.syncまたはjQuery.ajaxでコレクション全体を保存する「方法」

私はそれができることをよく知っており、かなりの数の場所を見ました( コレクション全体を保存するためのベストプラクティス? )。しかし、「正確にどのように」コードで書かれているのかまだわかりません。 (投稿では英語で説明しています。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?
 */
}

処理で「ビュー」が完了すると、サーバーに自身を「保存」するようにコレクションに指示する責任があります(一括更新/作成リクエストを処理できます)。

発生する質問:

  1. 「すべて一緒に配線する」ためのコードの記述方法
  2. コールバックの「正しい」場所と「成功/エラー」コールバックを指定する方法は何ですか?バックボーンでコールバックを登録する構文がわかりません...

それが本当にトリッキーな仕事であれば、ビュー内でjQuery.ajaxを呼び出してthis.successMethodまたはthis.errorMethod成功/エラーコールバックとして??機能しますか?

バックボーンの考え方と同期する必要があります-コレクション全体の同期など、何かが欠けていることは間違いありません。

81
PhD

私の当面の考えは、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
 }

});
64
bradgonesurfing

非常にシンプルな...

Backbone.Collection.prototype.save = function (options) {
    Backbone.sync("create", this, options);
};

...コレクションに保存方法を提供します。これは、何が変更されたかに関係なく、常にすべてのコレクションのモデルをサーバーにポストすることに注意してください。オプションは、通常のjQuery ajaxオプションです。

25
hacklikecrack

最終的に、「保存」のようなメソッドを持ち、その中に$ .ajaxを呼び出しました。 @brandgonesurfingが示唆するようにラッパークラスを追加する必要なく、それをより詳細に制御できました(ただし、私はこのアイデアを絶対に気に入っていますが): ajax呼び出しで...

これがつまずく人を助けることを願っています...

8
PhD

これは、クライアントとサーバーとの間の契約内容によって異なります。以下は、_/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')に変更できます。

5
carpeliam

答えは、サーバー側でコレクションをどのように処理するかによって異なります。

投稿に追加データを送信する必要がある場合、ラッパーモデルまたはリレーショナルモデルが必要になる場合があります

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);
    }
});
5
inf3rno

私が知っている古いスレッド、私がやったことは次のとおりです:

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();

かなり緊張します:)

3
Rene Weteling

また、Backboneコレクションには組み込みの保存機能がないことに驚きました。これを行うためにバックボーンコレクションに配置したものを次に示します。コレクション内の各モデルを繰り返し処理して、個別に保存することは絶対に避けたいです。また、Nodeを使用してバックエンドでBackboneを使用しているため、ネイティブBackbone.sync私の小さなプロジェクトでフラットファイルに保存します。ただし、コードはほとんど同じである必要があります。

    save: function(){                                                                                                                                                                                                                                                                                                                                                     
      Backbone.sync('save', this, {                                                                                                                                                                                                                                                                                                                                     
        success: function(){                                                                                                                                                                                                                                                                                                                                          
          console.log('users saved!');                                                                                                                                                                                                                                                                                                                              
        }                                                                                                                                                                                                                                                                                                                                                             
      });                                                                                                                                                                                                                                                                                                                                                               
    }
3
Mauvis Ledford

以下に簡単な例を示します。

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メソッドリクエストが送信されます。

2
Gaurav Gupta

私は次のようなものを試してみます:

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
    }
});

https://stackoverflow.com/a/11085198/137067

1
philfreo

受け入れられた答えはかなり良いですが、さらに一歩進んで、リスナーに適切なイベントが発生することを保証するコードを提供すると同時に、オプションの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);
}
1
Throttlehead

2017年にまだbackbone.jsを使用している人にとって、受け入れられた答えは機能していません。

ラッパーモデルでtoJSON()オーバーライドを削除し、モデルラッパーをインスタンス化するときにコレクションでtoJSONを呼び出してみてください。

new ModelWrapper(Collection.toJSON());
0
zeros-and-ones