【问题标题】:Backbone.js updating of models in a collectionBackbone.js 更新集合中的模型
【发布时间】:2013-05-24 18:44:27
【问题描述】:

假设您正在使用 Backbone.js 构建 Twitter 克隆。你有一系列推文。每条推文显然都是 Tweet 模型的一个实例。

您创建集合的一个实例,获取最新的 10 条推文,渲染它们并添加到 DOM。

到目前为止一切顺利。

如果您想在几分钟后调用服务器以查看是否有新推文到达,该怎么办?如何将新到达的推文添加到集合中?

如果您使用fetch() 方法,您将始终访问同一个 URL。没关系。有没有一种聪明的方法可以使用 Backbone/Underscore 过滤这些推文并将不在集合中的推文添加到集合中?

【问题讨论】:

  • 如果你想更新推文,实现实时服务器比让它轮询新推文要好得多。

标签: javascript jquery backbone.js


【解决方案1】:

假设您的每条推文都有一个唯一标识符(如果没有,您应该创建一个)。

您可以这样安排您的后端,默认情况下,如果您在没有任何参数的情况下调用 http://your.site.com/tweets,它会为您获取 10 条最新推文。

如果您致电http://your.site.com/tweets?last_tweet_id=BLAblaBlA,它将为您提供 10 条最新推文,这些推文位于您指定的 last_tweet_id 之后。

您可以通过实现 YourCollection.sync 方法覆盖将数据从后端获取到您的集合中的代码。

原因:Backbone.Collection首先尝试调用Collection.sync,如果没有实现,它会调用Backbone.sync函数,所以如果你实现了YourCollection.sync,它将被使用。这是 Backbone.Collection.fetch 函数的 sn-p:

(this.sync || Backbone.sync)('read', this, success, error);

所以你的同步会是这样的

var TweetCollection = Backbone.Collection.extend({
  model: TweetModel,
  sync: function(method, collection, success, error) {
    var requestData={};
    if(collection.length>0) {
        requestData.last_tweet_id=collection.last.id 
    }
    var params = {
        url:          "/tweet",
        type:         "POST",
        data:         requestData,
        success:      success,
        error:        error
    };
    $.ajax(params);
  }
}

您必须覆盖您的集合解析函数,以确保将响应附加到现有的模型数组中。

【讨论】:

  • 我很好奇你为什么在这里指定 POST 作为 http 方法。从 REST 的角度来看,GET 不是更传统吗?
【解决方案2】:

我不确定这在三月份是否可行,因为我最近才开始使用骨干网。但更好的解决方案可能是将标准 jQuery 选项传递给 Collection.fetch。

this.collection.fetch({data: {last_tweet: last_teet_id}});

Check out the jQuery documentation for a full list of parameters.

【讨论】:

    【解决方案3】:

    我相信这就是你要找的东西:

    yourCollection.fetch({add: true})
    

    然后,您可以将集合视图的渲染绑定到 add 事件:

    yourCollectionView.bind('add', this.render, this);
    

    不过,如果渲染很繁重,您需要通过超时来延迟它,以避免在每次添加到集合时立即调用它:

    yourCollectionView.bind('add', this.delayedRender, this);
    
    delayedRender: function() {
      var self = this;
      if (self.renderTimer) { clearTimeout(self.renderTimer); }
      self.renderTimer = setTimeout(function() {
        self.render();
        self.renderTimer = null;
      }, 300);
    }
    

    【讨论】:

      【解决方案4】:

      目前,开箱即用,没有。

      我使用的技术如下。你有你的 TweetCollection 扩展 Backbone.Collection 并且它有一个经典的 REST url,比如 "/tweets" 。您的后端仅发送 10 条最新记录(或第 1 页)。要获取第 2 页,您将使用类似“/tweets?page=2”的 url,后端将发送接下来的 10 条推文。问题是:如何在获取新记录的同时保留旧记录?

      我使用 2 个集合:

      • 第一个用于在屏幕上呈现推文。这是一个普通的 TweetCollection。
      • 第二个是用来从服务器获取页面的。我们称之为 TweetPageCollection。

      TweetPageCollection 使用以下 url 扩展了 TweetCollection:

       page: 1,
       url : function(){ return "/tweets?page=" + this.page; }
      

      现在在您的控制器代码中,您可以执行以下操作:

      initialize: function(){
        this.tweets = new TweetCollection();
        this.pages = new TweetPageCollection();
        this.pages.bind("refresh", this.newPageReceived);
      
        this.pages.page = 1;
        this.pages.fetch();
      
        this.tweet_list_view = new TweetListView({model: this.tweets});
      },
      getNextPage: function(){
        this.pages.page++;
        this.pages.fetch();
      },
      newPageReceived : function(page){
        // here you can check that the tweet is not already in the tweets collections
        this.tweets.add(page.toArray());
      }
      ...
      

      现在,当您想要获取新推文时,您调用 getNextPage(),当 XHR 成功时,您的视图将被刷新。

      可以应用相同的原则来重新获取最新的推文。 2 个集合,1 个获取,另一个集合获取。

      【讨论】:

        【解决方案5】:

        我认为这不是骨干问题。使用 Twitter 的 RESTful API,您可以使用可选的 since_id 参数。每次调用后,您的集合可以保存它获取的最新推文的 id。在你的 url 函数中使用这个 id,你只会收到更新的推文。

        【讨论】:

        • 这不是建立一个 Twitter 的界面。这是一个类似 Twitter 的应用程序。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-29
        • 1970-01-01
        相关资源
        最近更新 更多