AndrewJesaitis
AndrewJesaitis

Reputation: 482

Backbone collection is not updating when api is polled

I'm having some trouble getting change events to fire when a model is updated via polling of an endpoint. I'm pretty sure this is because the collection is not actually updated. I'm using the new option (update: true) in Backbone 0.9.9 that tries to intelligently update a collection rather than resetting it completely.

When I insert a console.log(this) at the end of the updateClientCollection function, it appears that this.clientCollection is not updating when updateClientCollection is called via setInterval. However, I do see that the endpoint is being polled and the endpoint is returning new and different values for clients.

managementApp.ClientListView = Backbone.View.extend({
  className: 'management-client-list',
  template: _.template( $('#client-list-template').text() ),

  initialize: function() {
    _.bindAll( this );
    this.jobId = this.options.jobId
    //the view owns the client collection because there are many client lists on a page
    this.clientCollection = new GH.Models.ClientStatusCollection();
    this.clientCollection.on( 'reset', this.addAllClients );
    //using the initial reset event to trigger this view's rendering
    this.clientCollection.fetch({
      data: {'job': this.jobId}
    });
    //start polling client status endpoint every 60s
    this.intervalId = setInterval( this.updateClientCollection.bind(this), 60000 );
  },

  updateClientCollection: function() {
    //don't want to fire a reset as we don't need new view, just to rerender
    //with updated info
    this.clientCollection.fetch({
      data: {'job': this.jobId},
      update: true,
      reset: false
    });
  },

  render: function() {
      this.$el.html( this.template() );
      return this;
  },

  addOneClient: function( client ) {
    var view = new managementApp.ClientView({model: client});
    this.$el.find( 'ul.client-list' ).append( view.render().el );
  },

  addAllClients: function() {
    if (this.clientCollection.length === 0) {
      this.$el.find( 'ul.client-list' ).append( 'No clients registered' );
      return;
    } 
    this.$el.find( 'ul.client-list' ).empty();
    this.clientCollection.each( this.addOneClient, this );
  }
});

managementApp.ClientView = Backbone.View.extend({
  tagName: 'li',
  className: 'management-client-item',
  template: _.template( $('#client-item-template').text() ),

  initialize: function() {
    _.bindAll( this );
    this.model.on( 'change', this.render );
  },

  render: function() {
    this.$el.html( this.template( this.model.toJSON() ) );
    return this;
  }
});

Upvotes: 0

Views: 234

Answers (1)

Cobby
Cobby

Reputation: 5454

From what I can gather from your code, you're only binding on the reset event of the collection.

According to the docs, Backbone.Collection uses the .update() method after fetching when you pass { update: true } as part of your fetch options.

Backbone.Collection.update() fires relevant add, change and remove events for each model. You'll need to bind to these as well and perform the relevant functions to update your UI.

In your case, you could bind to your existing addOneClient method to the add event on your collection.

In your ClientView class, you can bind to the change and remove events to re-render and remove the view respectively. Remember to use listenTo() so the ClientView object can easily clean-up the events when it remove()'s itself.

Upvotes: 0

Related Questions