[英]Polling a Collection with Backbone.js
我正在努力使Backbone.js Collection與服務器上發生的事情保持同步。
我的代碼類似於以下內容:
var Comment = Backbone.Model.extend({});
var CommentCollection = Backbone.Collection.extend({
model: Comment
});
var CommentView = Backbone.View.extend({ /* ... */ });
var CommentListView = Backbone.View.extend({
initialize: function () {
_.bindAll(this, 'addOne', 'addAll');
this.collection.bind('add', this.addOne);
this.collection.bind('refresh', this.addAll);
},
addOne: function (item) {
var view = new CommentView({model: item});
$(this.el).append(view.render().el);
},
addAll: function () {
this.collection.each(this.addOne);
}
});
var comments = new CommentCollection;
setInterval(function () {
comments.fetch();
}, 5000);
會發生什么事情,當提取注釋時,調用refresh
,注釋到CommentListView
底部的相同注釋 - 這是我對上面代碼的期望。
我想知道的是什么是“刷新”視圖的最佳方式,而不會失去任何“本地狀態”。
或者只是使用更簡單的添加到backbone的fetch方法:
this.fetch({ update: true });
當模型數據從服務器返回時,集合將被(有效地)重置,除非您傳遞{update:true},在這種情況下,它將使用update(智能地)合並獲取的模型。 - 骨干文檔
:-)
你想要做的是每隔幾秒刷新一次這個集合並添加新的評論。 我的建議是在你的后端處理這個問題。 從上次評論中發送最后一個時間戳,並僅在此日期向服務器詢問增量。
為此,請在您的收藏中:
CommentCollection = Backbone.Collection.extend({
url: function(){
return "/comments?from_time=" + this.last().get("created_at");
},
comparator: function(comment){
return comment.get("created_at");
}
});
在后端,根據from_time參數查詢數據庫。您的客戶端代碼不會更改以刷新視圖。
如果您因任何原因不想更改后端代碼,請在addAll函數中添加以下行:
addAll: function(){
$(this.el).empty();
this.collection.each(this.addOne);
}
Backbone.Collection.merge([選項])
基於@ Jeb上面的響應,我已將此行為封裝到Backbone擴展中,您可以將其復制並粘貼到.js文件中並包含在您的頁面中(包括Backbone庫本身之后)。
它為Backbone.Collection對象提供了一個名為merge
的方法。 它不是完全重置現有集合(如fetch
所做),而是將服務器響應與現有集合進行比較並合並它們的差異。
觸發所有預期事件以添加,刪除和更新模型。
選項哈希采用success
和error
回調,它們將作為參數傳遞(collection, response)
,並提供第三個回調選項,稱為complete
,無論成功或錯誤如何都會執行(主要用於輪詢方案)。
它會觸發名為“merge:success”和“merge:error”的事件。
這是擴展名:
// Backbone Collection Extensions
// ---------------
// Extend the Collection type with a "merge" method to update a collection
// of models without doing a full reset.
Backbone.Collection.prototype.merge = function(callbacks) {
// Make a new collection of the type of the parameter
// collection.
var me = this;
var newCollection = new me.constructor(me.models, me.options);
this.success = function() { };
this.error = function() { };
this.complete = function() { };
// Set up any callbacks that were provided
if(callbacks != undefined) {
if(callbacks.success != undefined) {
me.success = callbacks.success;
}
if(callbacks.error != undefined) {
me.error = callbacks.error;
}
if(callbacks.complete != undefined) {
me.complete = callbacks.complete;
}
}
// Assign it the model and url of collection.
newCollection.url = me.url;
newCollection.model = me.model;
// Call fetch on the new collection.
return newCollection.fetch({
success: function(model, response) {
// Calc the deltas between the new and original collections.
var modelIds = me.getIdsOfModels(me.models);
var newModelIds = me.getIdsOfModels(newCollection.models);
// If an activity is found in the new collection that isn't in
// the existing one, then add it to the existing collection.
_(newCollection.models).each(function(activity) {
if (_.indexOf(modelIds, activity.id) == -1) {
me.add(activity);
}
}, me);
// If an activity in the existing collection isn't found in the
// new one, remove it from the existing collection.
var modelsToBeRemoved = new Array();
_(me.models).each(function(activity) {
if (_.indexOf(newModelIds, activity.id) == -1) {
modelsToBeRemoved.push(activity);
}
}, me);
if(modelsToBeRemoved.length > 0) {
for(var i in modelsToBeRemoved) {
me.remove(modelsToBeRemoved[i]);
}
}
// If an activity in the existing collection is found in the
// new one, update the existing collection.
_(me.models).each(function(activity) {
if (_.indexOf(newModelIds, activity.id) != -1) {
activity.set(newCollection.get(activity.id));
}
}, me);
me.trigger("merge:success");
me.success(model, response);
me.complete();
},
error: function(model, response) {
me.trigger("merge:error");
me.error(model, response);
me.complete();
}
});
};
Backbone.Collection.prototype.getIdsOfModels = function(models) {
return _(models).map(function(model) { return model.id; });
};
簡單使用場景:
var MyCollection = Backbone.Collection.extend({
...
});
var collection = new MyCollection();
collection.merge();
錯誤處理使用場景:
var MyCollection = Backbone.Collection.extend({
...
});
var collection = new MyCollection();
var jqXHR = collection.merge({
success: function(model, response) {
console.log("Merge succeeded...");
},
error: function(model, response) {
console.log("Merge failed...");
handleError(response);
},
complete: function() {
console.log("Merge attempt complete...");
}
});
function handleError(jqXHR) {
console.log(jqXHR.statusText);
// Direct the user to the login page if the session expires
if(jqXHR.statusText == 'Unauthorized') {
window.location.href = "/login";
}
};
制作重復的集合。 獲取()它。 比較兩者以找到增量。 應用它們。
/*
* Update a collection using the changes from previous fetch,
* but without actually performing a fetch on the target
* collection.
*/
updateUsingDeltas: function(collection) {
// Make a new collection of the type of the parameter
// collection.
var newCollection = new collection.constructor();
// Assign it the model and url of collection.
newCollection.url = collection.url;
newCollection.model = collection.model;
// Call fetch on the new collection.
var that = this;
newCollection.fetch({
success: function() {
// Calc the deltas between the new and original collections.
var modelIds = that.getIdsOfModels(collection.models);
var newModelIds = that.getIdsOfModels(newCollection.models);
// If an activity is found in the new collection that isn't in
// the existing one, then add it to the existing collection.
_(newCollection.models).each(function(activity) {
if (modelIds.indexOf(activity.id) == -1) {
collection.add(activity);
}
}, that);
// If an activity in the existing colleciton isn't found in the
// new one, remove it from the existing collection.
_(collection.models).each(function(activity) {
if (newModelIds.indexOf(activity.id) == -1) {
collection.remove(activity);
}
}, that);
// TODO compare the models that are found in both collections,
// but have changed. Maybe just jsonify them and string or md5
// compare.
}
});
},
getIdsOfModels: function(models) {
return _(models).map(function(model) { return model.id; });
},
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.