Skip to content Skip to sidebar Skip to footer

Backbone - Trying To Rerender A View With The Next Or Previous Model In A Collection

I am trying to get into backbone and have the following which is an attempt at doing an image gallery. I am trying to use render with a model in a collection. I will show the first

Solution 1:

What it looks like you're looking for is a way to use the Collection to manipulate the next/prev stuff. What you currently have only puts it on the model. Here's a base Collection I use in my projects:

App.Collection = Backbone.Collection.extend({
  constructor: function(models, options) {
    var self = this;
    var oldInitialize = this.initialize;
    this.initialize = function() {
      self.on('reset', self.onReset);
      oldInitialize.apply(this, arguments);
    };
    Backbone.Collection.call(this, models, options);
  },
  onReset: function() {
    this.setActive(this.first());
  },
  setActive: function(active, options) {
    var cid = active;
    if ( active instanceof Backbone.Model ) {
      cid = active.cid;
    }
    this.each(function(model) {
      model.set('current', model.cid === cid, options);
    });
  },
  getActive: function() {
    return this.find(function(model) {
      return model.get('current');
    });
  },
  next: function() {
    return this.at(this.indexOf(this.getActive()) + 1);
  },
  prev: function() {
    return this.at(this.indexOf(this.getActive()) - 1);
  }
});

It's probably not perfect, but it works for me. Hopefully it can at least put you on the right track. Here is how I use it:

var someOtherCollection = App.Collection.extend({
    model: MyModel
});

Solution 2:

kalley's answer is right on, but I will throw in another example.

I would entertain the idea of keeping the current model inside of state model, and work from there. You can store other application information within the state model as well.

Your model declaration would look like the following. Notice I renamed previous to prev. Backbone.Model already has a previous method and we don't want to over-ride it.

var Model = Backbone.Model.extend({
  index:function() {
    return this.collection.indexOf(this);
  },
  next:function() {
    return this.collection.at(this.index()+1) || this;
  },
  prev:function() {
    return this.collection.at(this.index()-1) || this;
  }
});

Have a generic Backbone.Model that holds your selected model:

var state = new Backbone.Model();

In the view you will listen for changes to the state model and render accordingly:

var View = Backbone.View.extend({
  el: '#mig-container'
  template:_.template($('#mig-image-tmp').html()),
  events: {
    'click .prev' : 'prev',
    'click .next' : 'next'
  },
  initialize:function() {
    this.listenTo(state,'change:selected',this.render);
    state.set({selected:this.collection.at(0)});
  },
  render:function() {
    var model = state.get('selected');
    this.$el.html(this.template(model.toJSON()));
    return this;
  },
  next:function() {
    // get the current model
    var model = state.get('selected');

    /* Set state with the next model, fires a change event and triggers render.
       Unless you are at the last model, then no event will fire.
     */
    state.set({selected:model.next()});
  },
  prev:function() {
    var model = state.get('selected');
    state.set({selected:model.prev()});
  }
});

Here is a demo. I like the state model approach because I'm not storing application-state information within my models.

If you don't like the state model approach, you can always just throw it on the floor:

/ .. code above ../

initialize:function() {
  this.model = this.collection.at(0);
  this.render();
},
render:function() {
  this.$el.html(this.template(this.model.toJSON()));
  return this;
},
next:function() {
  this.model = this.model.nxt();
  this.render();
},
prev:function() {
  this.model = this.model.prev();
  this.render();
}

Post a Comment for "Backbone - Trying To Rerender A View With The Next Or Previous Model In A Collection"