使用Backbone.js轮询集合

sne*_*eeu 23 javascript ajax polling 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);
Run Code Online (Sandbox Code Playgroud)

会发生什么事情,当提取注释时,refresh被调用,相同的注释到底部CommentListView- 这是我对上面代码的期望.

我想知道的是什么是"刷新"视图的最佳方式,而不会失去任何"本地状态".

Jas*_*ker 31

或者只是使用更简单的添加到backbone的fetch方法:

this.fetch({ update: true });
Run Code Online (Sandbox Code Playgroud)

当模型数据从服务器返回时,集合将被(有效地)重置,除非您传递{update:true},在这种情况下,它将使用update(智能地)合并获取的模型.- 骨干文档

:-)


Jul*_*ien 16

你想要做的是每隔几秒刷新一次这个集合并添加新的评论.我的建议是在你的后端处理这个问题.从上次评论中发送最后一个时间戳,并仅在此日期向服务器询问增量.

为此,请在您的收藏中:

CommentCollection = Backbone.Collection.extend({
  url: function(){
    return "/comments?from_time=" + this.last().get("created_at");
  },
  comparator: function(comment){
    return comment.get("created_at");
  }
});
Run Code Online (Sandbox Code Playgroud)

在后端,根据from_time参数查询数据库.您的客户端代码不会更改以刷新视图.

如果您因任何原因不想更改后端代码,请在addAll函数中添加以下行:

addAll: function(){
  $(this.el).empty();
  this.collection.each(this.addOne);
} 
Run Code Online (Sandbox Code Playgroud)


Jas*_*ker 8

Backbone.Collection.merge([选项])

基于@ Jeb上面的响应,我已将此行为封装到Backbone扩展中,您可以将其复制并粘贴到.js文件中并包含在您的页面中(包括Backbone库本身之后).

它提供了一个名为mergeBackbone.Collection对象的方法.它不是完全重置现有集合(如同fetch),而是将服务器响应与现有集合进行比较并合并它们的差异.

  1. 添加了响应中的模型,但不包含现有集合中的模型.
  2. 会删除现有集合中的模型,但不会删除响应中的模型.
  3. 最后,它更新现有集合和响应中的模型属性.

触发所有预期事件以添加,删除和更新模型.

选项散列接受successerror将要传递回调(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; });
};
Run Code Online (Sandbox Code Playgroud)

简单使用场景:

var MyCollection = Backbone.Collection.extend({
  ...
});
var collection = new MyCollection();
collection.merge();
Run Code Online (Sandbox Code Playgroud)

错误处理使用场景:

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";                        
    }
};
Run Code Online (Sandbox Code Playgroud)