Backbone.js updating of models in a collection

后端 未结 5 1317
天涯浪人
天涯浪人 2021-01-30 11:47

Let\'s say you are building a Twitter clone with Backbone.js. You have a collection of tweets. Each tweet is obviously an instance of the Tweet model.

You create an inst

相关标签:
5条回答
  • 2021-01-30 12:29

    Lets assume that every one of your tweets has a unique identifier(if not, you should probably create one).

    You can structure your backend in such away that by default it gets you 10 latest tweets if you call http://your.site.com/tweets without any arguments.

    If you however call http://your.site.com/tweets?last_tweet_id=BLAblaBlA, it will give you 10 latest tweets that came after the last_tweet_id that you specified.

    You can override the code that gets the data from the backend into your Collection by implementing YourCollection.sync method.

    Reason: Backbone.Collection first tries to call Collection.sync and if its not implemented, it calls Backbone.sync function, so if you implement YourCollection.sync, it will be used. Here is the snippet from Backbone.Collection.fetch function:

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

    so your sync would be something like

    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);
      }
    }
    

    You would have to override your collections parse function to make sure that the response is appended to the existing array of models.

    0 讨论(0)
  • 2021-01-30 12:29

    Currently, out of the box, no.

    The technique I use is the following. You have your TweetCollection that extend Backbone.Collection and it has a classic REST url like "/tweets" . Your backend is sending only the 10 latest record (or page 1). To get page 2 you would use a url like "/tweets?page=2" and the backend would send the next 10 tweets. The question is really: how do you keep old record while fetching new one?

    I use 2 collections:

    • The first one is the one used to render the tweets on the screen. It is a normal TweetCollection.
    • The second one is the one used to get the pages from the server. Let's call it TweetPageCollection.

    TweetPageCollection extends TweetCollection with the following url:

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

    Now in your controller code you can do something like this:

    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());
    }
    ...
    

    Now when you want to fetch new tweets, you call getNextPage() and when the XHR will succeed your view will be refreshed.

    Same principles can be applied to refetch the latest tweets. 2 collections, 1 fetching, the other gathering fetches.

    0 讨论(0)
  • 2021-01-30 12:30

    I'm not sure if this was possible back in March as I only recently started using backbone. But a better solution may be to pass standard jQuery options into Collection.fetch.

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

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

    0 讨论(0)
  • 2021-01-30 12:34

    I believe this is what you were looking for:

    yourCollection.fetch({add: true})
    

    Then, you can bind your collection view's render to the add event:

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

    Though, if the render is heavy, you'll want to delay it with a timeout to avoid immediately calling it for every addition to the collection:

    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);
    }
    
    0 讨论(0)
  • 2021-01-30 12:41

    I don't think this is a backbone issue. Using Twitter's RESTful API you can use the optional since_id parameter. After each call your collection could save the id of the most recent tweet it has fetched. Use this id in your url function and you'll only receive newer tweets.

    0 讨论(0)
提交回复
热议问题