web-dev-qa-db-ja.com

Backbone.js部分モデルの更新

変更を保存するときに、モデルの変更されたプロパティのみを送信することはできますか?

ところで、この種の質問をする「公式の」Backbone.jsグループ/メーリングリストはありますか?

34
ggarber

現在、バックボーンはモデルの一部をサーバーに送信することをサポートしていません。それは興味深い追加ですが。

あなたが ソースを閲覧する なら、あなたはそれを見ることができますBackbone.sync(データストアとの通信を担当するバックボーンの一部)は、バックボーンの最も単純なコンポーネントの1つであり、jQueryまたはZeptoでajaxサポートをラップするだけです。


[〜#〜]更新[〜#〜]

バックボーンバージョン0.9.10以降、モデルの部分的な更新は、

model.save(attrs, {patch: true})
33
Andrew Hare

バックボーンはそのままではこれをサポートしていませんが、それを実現するためのすべてのツールがあります。 Backbone.syncを見ると、モデルでtoJSONを呼び出して、送信する実際のデータを取得していることがわかります。これを調整する必要があるかもしれませんが、その要点は次のとおりです。

initialize: function(){
  this.dirtyAttributes = {}
},
set: function(attrs, options){
  Backbone.Model.prototype.set.call(this, attrs, options);
  _.extend(this.dirtyAttributes, attrs);
},
toJSON : function(){
  json = this.dirtyAttributes;
  this.dirtyAttributes = {};
  return json;
}

完全なソリューションが必要な場合は、同じロジックを設定解除、クリア、保存などに適用する必要があります。しかし、これを行う方法を理解していると思います。ダーティ属性のリセットをtoJSON関数に入れましたが、それは実際には(コールバックを保存するときに)成功コールバックにあるはずです。

46
Julien

更新:バックボーンバージョン0.9.10以降、部分更新はネイティブでサポートされます

model.save(attrs, {patch: true})


.9.9まで backbone.jsライブラリファイルを直接編集しないアプローチ。次のコードをアプリケーションのjsファイルに追加し、backbone.jsがロードされた後にそれをロードするだけです。

//override the Backbone.sync to send only the changed fields for update (PUT) request
var Original_BackboneSync = Backbone.sync;

Backbone.sync = function(method, model, options) {
    /* just handle the data picking logic for update method */
    if (!options.data && model && method == 'update') {
        options.contentType = 'application/json';
        options.data = JSON.stringify(model.changedAttributes() || {});
    }

    //invoke the original backbone sync method
    return Original_BackboneSync.apply(this, arguments);
};

//Tested in Backbone.js 0.9.1
6
Jay Kumar

_Backbone.sync_を上書きする代わりに、_Model.sync_メソッド内で行うことができます。そこではmodel.changedAttributes()にアクセスできないため、このメソッド内では常にfalseを返すようにしてください。

_sync: (method, model, options) ->
  if method is "update"
    options.contentType = 'application/json'
    changedData = {}
    for attr in _.keys(options.changes)
      changedData[attr] = model.get(attr)
    options.data = JSON.stringify changedData

  Backbone.sync method, model, options
_
2
mateusmaso

ここで提案されているいくつかの手法を試しましたが、結局、Backbone.ModelとBackbone.syncを直接変更することにしました。私が提供したかったのは、バックボーンメソッドのオーバーライドについて私のチームの開発者に指示する必要のない、この機能を提供するための最小限の侵襲的な方法でした。エラーが発生しやすい。私のソリューションでは、モデルの「保存」メソッドにオプションを渡すだけです。例えば:

//Note that this could be from your view or anywhere you're invoking model.save
saveToModel : function() {
    this.model.save({
        field1 : field1Value,
        field2 : field2Value,
        field3 : field3Value
    }, {partialUpdate : true}
}

この機能を有効にするために、Backbone.Model.saveとBackbone.syncにいくつかのマイナーな変更を加えました。これがBackbone.Model.saveへの変更です。

//If a partialUpdate is required, create a member on the options
//hash called updateAttrs and set it to attrs
if (options.partialUpdate != "undefined" && options.partialUpdate) {
    options.updateAttrs = attrs;
}
//--->>>Put the block above right above the return line
return (this.sync || Backbone.sync).call(this, method, this, options);

ここで何が起こるかというと、partialUpdateがオプションとして渡されると、updateAttrsという新しいメンバーがオプションハッシュに作成されます。オプションハッシュは自動的にBackbone.syncに渡されます。

Backbone.syncについて、次の条件を変更しました。

// Ensure that we have the appropriate request data.
if (!params.data && model && (method == 'create' || method == 'update')) {
    params.contentType = 'application/json';
    params.data = JSON.stringify(model.toJSON());
}

に...

// Ensure that we have the appropriate request data.
if (!params.data && model && (method == 'create' || method == 'update')) {
    params.contentType = 'application/json';

    //If doing a partial model update, then grab the updateAttrs member
    //from options. Will not interfere with line directly below as params.data
    //will have been set.
    params.data = (options.partialUpdate != "undefined" && options.partialUpdate)
                ? params.data = JSON.stringify(options.updateAttrs)
                : params.data = JSON.stringify(model.toJSON());
}

追加の条件チェックを追加して、partialUpdateが設定されているかどうかを確認し、設定されている場合は、params.dataをoptions.updateAttrsに設定します。これは、jquery Ajaxメソッドに渡されます。

2
Brendan Delumpa

ここでの答えのほとんどは、直接的または間接的にsync関数を変更することです。これを克服するための私の小さなトリックは次のとおりです。

model.saveを呼び出すとき、バックボーンが同期を呼び出そうとするときに$.ajaxとともに渡される2番目のパラメーターを実際に渡すことができます。私は次のように部分的な更新を行いました。送信するフィールドを明示的に指定することです。

/**
 * On user clicking on "mark important"
 */
onMarkImportantBtnClick: function() {
    var marked = this.model.get('UserFeed.marked_important'),
        data = {
            UserFeed: {
                marked_important: !marked
            }
        };
    this.model.save(data, {data: JSON.stringify(data), contentType: 'application/json'});
}

このアクションにより、モデルの属性が正しく更新され、さらにJSON.stringifyで言及されたデータのみがサーバーに送信されます。 contentTypeがここに必要です、より良い

これは、Backbone.syncこれらの行がある であり、data属性を渡すことでそれを否定しているためです。

if (!options.data && model && (method == 'create' || method == 'update')) {
    params.contentType = 'application/json';
    params.data = JSON.stringify(model.toJSON());
}

このページのクレジット: https://plus.google.com/103858073822961240171/posts/1gTcu6avmWQ

注:このモデルは、powmediaの DeepModel から継承され、ネストされたモデル属性をサポートします


編集

Backbone 0.9.9以降、 patch オプションが追加されたため、このトリックは以前のバージョンにのみ適用されます。

ダーティデータのみをサーバーに送信するには、save{patch: true}を指定します。

this.model.save(modifiedData, {patch: true});

それを指摘してくれた@リンカーンBに感謝します。

1
Lionel Chan

特定の属性のみを持つサーバーに更新要求を送信する必要がある場合は、同様のことを行うことができます。

saveAttributes: (attributes, options={}) ->
  data = {}
  _(attributes).each (attribute) =>
    data[attribute] = @get(attribute)

  params =
    data: $.param(data)

  _.extend(params, options)

  Backbone.sync('update', null, params)

詳細: https://github.com/documentcloud/backbone/pull/57

_.extend Backbone.Model.prototypeで拡張できます

1

Jayyy Vの(非常に良い)回答を使用して、同期機能がホワイトリストを取得するように少し書き直して、保存するキーの配列を指定できるようにします。

var Original_BackboneSync = Backbone.sync;
Backbone.sync = function(method, model, options) {
    /* check if a whitelist was in options */
    if (options.whitelist) {
      options.contentType = 'application/json';
      /* use underscore method for picking only whitelisted attributes to save */
      options.data = JSON.stringify(_.pick(model.attributes, options.whitelist));
    }

    //invoke the original backbone sync method
    return Original_BackboneSync.apply(this, arguments);
};
0
Bastian Albers

実際には、これを達成するためのはるかに簡単な方法があります

backbone.jsの1145行目を見ると、

_// Ensure that we have the appropriate request data.
    if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
      params.contentType = 'application/json';
      params.data = JSON.stringify(options.attrs || model.toJSON(options));
    }
_

これは、オプションにデータを入れることで、xhrのデータ部分をオーバーライドできることを意味します

バックボーンの保存にはmodel.save([attributes], [options])が必要なので

しかし、idなどの属性は適切な保存に不可欠である可能性があることを覚えておいてください

_model.save( {}, { data: JSON.stringify(data) } ) ; 
_

だからあなたはこのようなことをするべきです

_var data = { id : model.id , otherAttributes : 'value' }  ;  
_

または

_var data = model.toJSON () ;
remove data.tempData ; 
_

最後に

_model.save( {}, { data : JSON.stringify(data) } );
_

これは私にとって非常にうまくトリックを行い、フェッチ、保存、削除などのxhrを備えたバックボーンで使用できます...

保存、同期、またはtoJSONを使用した混乱は非常に間違っている

0
Pascal

@Julienの投稿に基づいて構築する:これをモデルに追加すると、モデル全体ではなく、渡した属性のみが送信されます。引き続きデフォルトの動作に保存を使用できます。パラメーターとして渡す属性を送信するだけの場合は、partialSaveを使用できます。私はこれをテストしましたが、うまくいきました。

  partialSave: function(attr, options) { //use this method instead of save()
    this.dirtyAttributes = attr;
    this.save(attr, options);
  },

  toJSON: function() { //overrides Backbone.Model.prototype.toJSON
    if (this.dirtyAttributes) {
      var attr = this.dirtyAttributes;
      this.dirtyAttributes = null;
      return attr;
    }
    return Backbone.Model.prototype.toJSON.apply(this, arguments);
  },
0
Daniel

拡張モデルを作成しました。

var CModel = Backbone.Model.extend({
    save: function(attributes, options) {
        if(_.isUndefined(options)) {
            options = {};
        }

        var isNeedAttrsRefresh = false,
            basicAttributes = null;

        if(!_.isUndefined(options.fields)) {
            basicAttributes = _.clone(this.attributes);
            var newAttributes = {};
            _.each(this.attributes, function(value, name) {
                if(options.fields.indexOf(name) > -1) {
                    newAttributes[name] = value;
                }
            });
            this.attributes = newAttributes;
            isNeedAttrsRefresh = true;
        }

        this.isSaving = true;
        var result = Backbone.Model.prototype.save.apply(this, arguments);
        this.isSaving = false;

        if(isNeedAttrsRefresh) {
            this.attributes = basicAttributes;
        }

        return result;
    }
});

使用例:

var CommentModel = CModel.extend({ ... }

そしてフィールドに保存を許可しました:

comment.save(null, {    fields: ['message', 'entry_id', 'module_id', 'parent_id'] });
0
Oleksandr Knyga