2011-03-11 102 views
33

保存更改时是否可以发送模型的修改属性?Backbone.js部分模型更新

顺便说一句,有没有任何“官方”Backbone.js组/邮件列表来问这样的问题?

+5

这是现在支持为0.9.9版本,如果你只希望改变的属性发送到服务器,调用model.save(attrs,{patch:true})。只需传入的属性即可获得到服务器的HTTP PATCH请求。 http://backbonejs.org/#Model-save – Ben 2013-01-06 19:18:50

回答

33

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

如果你browse the source你可以看到Backbone.sync(负责与数据存储通信的骨干部分)是骨干网中最简单的组件之一,并简单地将Ajax支持包装在jQuery或Zepto中。


UPDATE

开始骨干版本0.9.10,局部模型更新通过

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

谢谢。例如,JavascriptMVC支持该功能,我同意这将是一个很好的补充。 – ggarber 2011-03-11 16:09:04

+3

补丁不是'创建'一个新对象和'更新'一个对象的好主意,它不是一个宁静的设计。我推荐覆盖'sync'方法 – sjbwylbs 2013-04-21 15:25:04

+4

看起来像只发送更改字段的最简单方法是'模型.save(model.changedAttributes(),{patch:true});'。那是在Backbone 1.0.0。 – 2013-08-02 17:03:09

46

骨干原生支持不支持这个开箱即用,但你拥有所有的工具做到这一点。 如果你看Backbone.sync,你会看到它在你的模型上调用JSON来获取实际的数据发送。现在你可能要调整了这一点,但这里是它的要点:

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函数中,但它确实应该在成功回调中(当调用保存时)。

+0

谢谢你的回答。我接受了另一个,因为他速度更快:-)。 – ggarber 2011-03-11 16:08:37

+8

@gustavogb好吧,谢谢让StackOverflow变得更糟。 – 2012-07-12 14:03:17

+0

我会更进一步,只标记为实际已更改的脏属性。将属性值设置为原始值(从服务器加载时)应将其标记为干净(不再脏)。这在lib中会有意义吗?我应该提交补丁吗?请注意'{patch:true}'的当前行为不会这样做。 – 2013-04-30 13:01:10

1

如果您需要发送更新请求到服务器只是一个特定的属性,你可以做同样的事情:对

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/573

您可以_.extend Backbone.Model.prototype

扩展它
+0

后面马上将所有字段标记为“脏”,我必须指定'A'url'属性或函数。错误:必须指定'url'属性或函数 backbone_rails_sync.js:15' – lulalala 2012-08-27 08:21:46

2

我尝试了几个这里提出的技术,但最终决定直接修改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方法。

6

UPDATE:开始骨干版本0.9.10,部分更新是通过本地

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


支持直到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 
+0

这是一项很酷的技术。 – 2012-05-21 18:41:41

+0

这个版本似乎比原生版更好! – exussum 2013-06-26 12:35:45

+0

'changedAttributes'只包含最后一次调用到'.set()'的变化,所以如果你做了'm.set('p1',1); m.set('p2',2); m.save();'它只会发送'{p2:2}'不是所有更新的字段。 – CodingWithSpike 2016-03-15 20:50:12

2

而是覆盖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 
0

使用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); 
}; 
1

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

当你打电话给model.save时,你实际上可以传入第二个参数,当Backbone尝试调用同步时将传递给$.ajax。我不喜欢这样的部分更新,更明确地规定哪些字段提交:

/** 
* 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.synchas these lines,并且我们通过传递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以支持嵌套模型属性


编辑自骨干0.9.9,patch选项已被添加

所以这一招只适用于以前的版本。

要只提交脏数据传回服务器,供应{patch: true}save,这样

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

感谢@Lincoln B中指点一下。

+1

最好的答案在这里,谢谢你的来源。 Backbone 0.9.9增加了{path:true}来保存,但是如果你现在不能升级,这是理想的事情。我个人定义了一个单独的补丁,如补丁:(attributes,options = {}) - > this.save(attributes,{data:JSON.stringify(attributes)}) – 2013-01-17 23:41:38

+0

是的。此解决方案仅适用于较旧的Backbone版本。新的“补丁”很酷! – 2013-01-18 01:41:58

0

在@ 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); 
    }, 
0

事实上,有实现这一

的更简单的方法,如果你看一下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

我创建了扩展模型。用法

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