2012-09-05 58 views
10

我有一個Backbone集合,包含一系列模型。一次保存多個Backbone模型

每當一個特定的屬性被設置在一個模型,它被保存,計算的負載斷火和UI重新渲染。

但是,我希望能夠一次設置多個模型的屬性和只能做儲蓄和重新描繪,一旦他們所有的設置。當然,我不想爲一個操作發出多個http請求,並且肯定不希望重新渲染界面十次。

我希望能找到Backbone.Collection)保存方法,將工作哪些型號hasChanged(一起重擊他們作爲JSON和歡送到後端。然後可以通過集合上的事件觸發重新呈現。沒有這樣的運氣。

這似乎是一個很常見的需求,所以很奇怪,爲什麼骨幹網沒有實現。這是否違背RESTful體系結構,將幾件事情保存到單個端點?如果是這樣,那又如何?使1000個請求保留1000個小項目是不現實的。

那麼,是唯一的解決方案,用我自己的save方法來增強Backbone.Collection,它遍歷所有的模型,併爲所有已更改的json構建json,並將其發送到後端?或者沒有人有一個整潔的解決方案(或者我只是錯過了一些東西!)?

+3

相關:http://stackoverflow.com/questions/11819662/why-does-backbone-not-have-a-save-put-post-method-for-its-collections-is-i/11819965#11819965 | http://stackoverflow.com/questions/11042292/extend-backbone-sync-to-batch-sync | http://stackoverflow.com/questions/511281/patterns-for-handling-batch-operations-in-rest-web-services | http://stackoverflow.com/questions/8529919/how-to-update-a-set-of-records-using-backbone-js-rails – fguillen

回答

4

我已經結束了用一些方法來處理這個問題,以增強Backbone.Collection。

的saveChangeMethod創建要傳遞給Backbone.sync一個假人模型。模型中所有主幹的同步方法需求都是它的url屬性和JSON方法,所以我們可以很容易地將其敲除。

在內部,模型的toJSON方法只返回其屬性的副本(要發送到服務器),所以我們可以愉快地使用剛剛返回模型數組的toJSON方法。 Backbone.sync對此進行了字符串處理,這使我們只知道屬性數據。

成功時,saveChanged觸發關閉事件的集合進行一次處理。使用了一些代碼,它可以爲每個批次模型中已更改的每個屬性觸發特定事件一次。

Backbone.Collection.prototype.saveChanged = function() { 
    var me = this, 
     changed = me.getChanged(), 
     dummy = { 
      url: this.url, 
      toJSON: function() { 
       return changed.models; 
      } 
     }, 
     options = { 
      success: function (model, resp, xhr) { 
       for (var i = 0; i < changed.models.length; i++) { 
        changed.models[i].chnageSilently(); 
       } 
       for (var attr in changed.attributes) { 
        me.trigger("batchchange:" + attr); 
       } 
       me.trigger("batchsync", changed); 
      } 
     }; 
    return Backbone.sync("update", dummy, options); 
} 

然後,我們只需要對集合的getChanged()方法。這將返回一個對象2周的特性,改變後的模型的陣列以及哪些屬性已改變的對象檢舉:

Backbone.Collection.prototype.getChanged = function() { 
    var models = [], 
     changedAttributes = {}; 
    for (var i = 0; i < this.models.length; i++) { 
     if (this.models[i].hasChanged()) { 
      _.extend(changedAttributes, this.models[i].changedAttributes()); 
      models.push(this.models[i]); 
     } 
    } 
    return models.length ? {models: models, attributes: changedAttributes} : null; 
} 

雖然這是預期的用途骨架「改變的模型」範式,整點的輕微濫用的配料是,當模型改變時,我們不希望發生任何事情(即任何事件發生)。

因此,我們必須將{silent:true}傳遞給模型的set()方法,所以使用backbone的hasChanged()來標記等待保存的模型是有意義的。當然,如果你爲了其他目的而默默地改變模型,這會有問題 - collection.saveChanged()也會保存它們,所以值得考慮設置一個替代標誌。在任何情況下,如果我們這樣做,當保存時,我們需要確保骨幹現在認爲模型沒有改變(不觸發它們的改變事件),所以我們需要手動操縱模型,就好像它沒有改變。該saveChanged()在我們改變模型方法進行迭代,並呼籲模式,這基本上是骨幹model.change()方法不觸發這個changeSilently()方法:

Backbone.Model.prototype.changeSilently = function() { 
    var options = {}, 
    changing = this._changing; 
    this._changing = true; 
    for (var attr in this._silent) this._pending[attr] = true; 
    this._silent = {}; 
    if (changing) return this; 

    while (!_.isEmpty(this._pending)) { 
     this._pending = {}; 
     for (var attr in this.changed) { 
     if (this._pending[attr] || this._silent[attr]) continue; 
     delete this.changed[attr]; 
     } 
     this._previousAttributes = _.clone(this.attributes); 
    } 
    this._changing = false; 
    return this; 
} 

用法:

model1.set({key: value}, {silent: true}); 
model2.set({key: value}, {silent: true}); 
model3.set({key: value}, {silent: true}); 
collection.saveChanged(); 

RE。 RESTfulness ..對集合的端點執行PUT以更改它的某些記錄是不正確的。從技術上講,PUT應該取代整個集合,但直到我的應用程序實際上需要替換整個集合時,我很樂意採取實用的方法。

1

你可以定義一個新的資源來完成這種行爲,你可以稱它爲MyModelBatch

您需要實現在你的服務器端的新資源是能夠消化的模型的Array和執行正確的動作:CREATEUPDATEDESTROY

你也需要實現一個Model在骨幹網客戶端與一個屬性這是模式的陣列和專用url不利用id

關於重新渲染的事情,我建議你嘗試有一個查看每個型號所以會有儘可能多的呈現作爲模型已經改變,但他們會詳細重新呈現不重複。

+0

謝謝。根據您使用臨時模型的建議,我注意到Backbone.sync只查看模型的url屬性和toJSON方法,因此不是使用實際的模型,我們可以很容易地僞造一個用於同步的模型。 toJSON只返回要被字符串化的模型屬性的副本,所以我們可以使用它返回我們的模型數組。看到我的答案。 – hacklikecrack