Backbone.js обновление моделей в коллекции

Скажем, вы создаете клон Twitter с Backbone.js. У вас есть коллекция твитов. Каждый твит является, очевидно, экземпляром модели Tweet.

Вы создаете экземпляр коллекции, извлекаете последние 10 твитов, визуализируете их и добавляете в DOM.

Пока все хорошо.

Что, если вы хотите сделать звонок на сервер через несколько минут, чтобы узнать, появились ли какие-либо новые твиты? Как вы можете добавить недавно полученные твиты в коллекцию?

Если вы используете метод fetch(), вы постоянно используете один и тот же URL-адрес. Это здорово. Есть ли умный способ, с помощью которого я могу использовать Backbone/Underscore для их фильтрации и добавления твитов, отсутствующих в коллекции, в коллекцию?

Ответ 1

Предположим, что каждый из ваших твитов имеет уникальный идентификатор (если нет, вы, вероятно, должны создать его).

Вы можете структурировать свой сервер таким образом, чтобы по умолчанию он получил 10 последних твитов, если вы вызываете http://your.site.com/tweets без каких-либо аргументов.

Если вы однако звоните 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:

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

Вам нужно будет переопределить функцию разбора коллекций, чтобы убедиться, что ответ добавлен к существующему массиву моделей.

Ответ 2

Я не уверен, что это возможно в марте, поскольку я только недавно начал использовать магистраль. Но лучшим решением может быть передача стандартных параметров jQuery в Collection.fetch.

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

Проверьте документацию jQuery для полного списка параметров.

Ответ 3

Я считаю, что это то, что вы искали:

yourCollection.fetch({add: true})

Затем вы можете привязать визуализацию вида коллекции к событию добавления:

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

В настоящее время из коробки нет.

Используемая мной техника заключается в следующем. У вас есть твит-код, который расширяет Backbone.Collection и имеет классический URL-адрес REST, например "/tweets". Ваш сервер передает только 10 последних записей (или стр. 1). Чтобы получить страницу 2, вы использовали бы URL-адрес, например "/tweets? Page = 2", и бэкэнд отправил следующие 10 твитов. На самом деле вопрос: как вы сохраняете старую запись, получая новую?

Я использую 2 коллекции:

  • Первый - это тот, который используется для отображения твитов на экране. Это обычный твит-код.
  • Второй - тот, который используется для получения страниц с сервера. Позвольте называть его TweetPageCollection.

TweetPageCollection расширяет TweetCollection со следующим URL:

 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

Я не думаю, что это проблема с позвоночником. Используя API Twitter RESTful, вы можете использовать необязательный параметр from_id. После каждого вызова ваша коллекция может сохранить идентификатор самого последнего твита, который он выбрал. Используйте этот идентификатор в своей функции url, и вы получите только новые твиты.