2011-03-11 93 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'] });