Javascript Backbone.js 部分模型更新

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5273369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:26:23  来源:igfitidea点击:

Backbone.js partial model update

javascriptbackbone.js

提问by ggarber

Is it possible to send just the modified properties of a model when saving the changes?

保存更改时是否可以仅发送模型的修改后的属性?

BTW, Are there any "official" Backbone.js group/mailing list to ask this kind of questions?

顺便说一句,是否有任何“官方”Backbone.js 组/邮件列表可以提出此类问题?

采纳答案by Andrew Hare

Currently backbone does not support sending part of the model to the server. It would be an interesting addition though.

目前主干不支持将模型的一部分发送到服务器。不过,这将是一个有趣的补充。

If you browse the sourceyou can see that Backbone.sync(the part of backbone that is responsible for communicating with the data store) is one of the simplest components in backbone and simply wraps the ajax support in jQuery or Zepto.

如果您浏览源代码,您会看到Backbone.sync(负责与数据存储通信的主干部分)是主干中最简单的组件之一,并且简单地将 ajax 支持包装在 jQuery 或 Zepto 中。


UPDATE


更新

starting backbone version 0.9.10, partial model update is supported natively via

从主干版本 0.9.10 开始,通过本地支持部分模型更新

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

回答by Julien

Backbone does not support this out of the box, but you have all the tools to make that happen. If you look at Backbone.sync you will see that it calls toJSON on your model to get the actual data to send. Now you might have to tweak this out, but here is the gist of it:

Backbone 不支持开箱即用,但您拥有实现这一目标的所有工具。如果您查看 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;
}

If you want a complete solution you need to apply the same logic to unset, clear, save, etc. But I guess you get how to do this. I put the reset of the dirty attributes in the toJSON function, but it should really be in the success callback (when calling save).

如果你想要一个完整的解决方案,你需要应用相同的逻辑来取消设置、清除、保存等。但我想你知道如何做到这一点。我把脏属性的重置放在 toJSON 函数中,但它真的应该在成功回调中(调用保存时)。

回答by Jay Kumar

UPDATE: starting backbone version 0.9.10, partial update is supported natively via

更新:从主干版本 0.9.10 开始,通过本地支持部分更新

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


Until 0.9.9An approach without directly editing the backbone.js library file. Just the add the following code in application js file and load it after backbone.js gets loaded.


直到 0.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

回答by mateusmaso

Instead of overwriting Backbone.syncyou could just do it inside the Model.syncmethod. Since you can't access model.changedAttributes()there, be sure to always return false inside this method.

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

回答by Brendan Delumpa

I tried several of the techniques that were suggested here, but in the end, decided to modify Backbone.Model and Backbone.sync directly. What I wanted to provide was a minimally invasive method for providing this functionality that didn't require instructing developers on my team on overriding backbone methods; just too prone to error. My solution involves only passing an option to the model's "save" method. For example:

我尝试了这里推荐的几种技术,但最终决定直接修改 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}
}

Now, to enable this functionality, I made some very minor modifications to Backbone.Model.save and Backbone.sync. Here's the change to Backbone.Model.save:

现在,为了启用这个功能,我对 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);

What happens here is that if partialUpdate is passed as an option, then a new member called updateAttrs is created on the options hash. The options hash is automatically passed to Backbone.sync.

这里发生的情况是,如果将 partialUpdate 作为选项传递,则会在选项哈希上创建一个名为 updateAttrs 的新成员。选项哈希会自动传递给 Backbone.sync。

For Backbone.sync, I changed the following conditional:

对于 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());
}

to...

到...

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

Adding the extra conditional checks to see if partialUpdate was set, then if it is, set params.data to options.updateAttrs. This will then be passed to the jquery Ajax method.

添加额外的条件检查以查看是否设置了 partialUpdate,如果是,则将 params.data 设置为 options.updateAttrs。然后将其传递给 jquery Ajax 方法。

回答by Dmitry Polushkin

If you need to send update request to a server with just a specific attributes, you can do something similar:

如果您需要向仅具有特定属性的服务器发送更新请求,您可以执行类似的操作:

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

  params =
    data: $.param(data)

  _.extend(params, options)

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

More info on that: https://github.com/documentcloud/backbone/pull/573

更多信息:https: //github.com/documentcloud/backbone/pull/573

You can extend it with _.extend Backbone.Model.prototype

你可以扩展它 _.extend Backbone.Model.prototype

回答by Lionel Chan

Most of the answers here are either direct or indirectly modify the syncfunction. Here is my little trick to overcome this:

这里的大多数答案都是直接或间接修改sync函数。这是我克服这个问题的小技巧:

When you call your model.save, you can actually pass in the second parameter that will be passed along with the $.ajaxwhen Backbone is trying to call the sync. I did the partial update like this, more of explicitly specifying which fields to submit:

当您调用您的 时model.save,您实际上可以传入第二个参数,该参数将与$.ajaxBackbone 尝试调用同步时一起传递。我做了这样的部分更新,更多的是明确指定要提交的字段:

/**
 * 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'});
}

This action updated my model attributes correctly, plus sending to the server only the data that mentioned in the JSON.stringify. contentTypeis required here, better

此操作正确更新了我的模型属性,并仅将 .csv 文件中提到的数据发送到服务器JSON.stringifycontentType这里需要,更好

This is because Backbone.synchas these lines, and we are negating it by passing dataattribute:

这是因为Backbone.sync有这些行,我们通过传递data属性来否定它:

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

Credit to this page: https://plus.google.com/103858073822961240171/posts/1gTcu6avmWQ

归功于此页面:https: //plus.google.com/103858073822961240171/posts/1gTcu6avmWQ

Note: This model inherited from powmedia's DeepModelto support nested model attributes


Edit

注:此模型继承自 powmedia 的DeepModel,支持嵌套模型属性


Edit

Since Backbone 0.9.9, patchoption has been added so this trick is only applicable to previous version.

自 Backbone 0.9.9 以来,patch已添加选项,因此此技巧仅适用于以前的版本。

To submit only the dirty data back to your server, supply {patch: true}in your save, such that

要仅将脏数据提交回您的服务器,请{patch: true}在您的 中提供save,以便

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

Thanks @Lincoln B for pointing it out.

感谢@Lincoln B 指出。

回答by Daniel

Building on @Julien's post: You can add this to your model, and it will only send the attributes that you pass in as opposed to the entire model. You can still use save for the default behavior, and you can use partialSave when you want to just send those attributes that you pass in as a parameter. I have tested this, and it worked for me.

基于@Julien 的帖子:您可以将其添加到您的模型中,它只会发送您传入的属性,而不是整个模型。您仍然可以将 save 用于默认行为,并且当您只想发送作为参数传入的那些属性时,您可以使用 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);
  },

回答by Pascal

In fact there is a much simpler way of achieving this

事实上,有一个更简单的方法来实现这一目标

if you look at backbone.js line 1145 you will see that

如果您查看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));
    }

Which means that you may override the data part of the xhr by putting data in your options

这意味着您可以通过将数据放入选项来覆盖 xhr 的数据部分

Since backbone save requires model.save([attributes], [options])

由于主干保存需要 model.save([attributes], [options])

But remember that attributes like id might be essential to proper saving

但请记住,像 id 这样的属性对于正确保存可能是必不可少的

Example

例子

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

So you should be doing something like this

所以你应该做这样的事情

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

or

或者

var data = model.toJSON () ;
remove data.tempData ; 

Finally

最后

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

This do the trick quite well for me and could be used with any backbone with xhr such as fetch, save, delete, ...

这对我来说非常有用,并且可以与任何具有 xhr 的主干一起使用,例如获取、保存、删除......

Messing with save, sync or toJSON look so wrong

弄乱保存、同步或 toJSON 看起来很错误

回答by Oleksandr Knyga

I created extended Model.

我创建了扩展模型。

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

Example of usage:

用法示例:

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

And allowed fields to save:

并允许字段保存:

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