Search code examples
javascriptbackbone.jspaginationmarionettebackbone.paginator

Backbone.Paginator infinite mode, with Marionette


In my Marionette app, I have a Collection view, with a childView for it's models.

The collection assigned to the CollectionView is a PageableCollection from Backbone.paginator. The mode is set to infinite.

When requesting the next page like so getNextPage(), the collection is fetching data and assigning the response to the collection, overwriting the old entries, though the full version is store in collection.fullCollection. This is where I can find all entries that the CollectionView needs to render.

Marionette is being smart about collection events and will render a new childView with it's new model when a model is being added to the collection. It will also remove a childView when it's model was removed.

However, that's not quite what I want to do in this case since the collection doesn't represent my desired rendered list, collection.fullCollection is what I want to show on page.

Is there a way for my Marionette view to consider collection.fullCollection instead of collection, or is there a more appropriate pagination framework for Marionette?

Here's a fiddle with the code

For those who don't like fiddle:

App = Mn.Application.extend({});

// APP
App = new App({
  start: function() {
    App.routr = new App.Routr();
    Backbone.history.start();
  }
});

// REGION
App.Rm = new Mn.RegionManager({
  regions: {
    main: 'main',
    buttonRegion: '.button-region'
  }
});

// MODEL
App.Model = {};
App.Model.GeneralModel = Backbone.Model.extend({});

// COLLECTION
App.Collection = {};
App.Collection.All = Backbone.PageableCollection.extend({
  model: App.Model.GeneralModel,

  getOpts: function() {
    return {
      type: 'POST',
      contentType: 'appplication/json',
      dataType: 'json',
      data: {skip: 12},
      add: true
    }
  },

  initialize: function() {

    this.listenTo(Backbone.Events, 'load', (function() {
      console.log('Load more entries');

      // {remove: false} doesn't seem to affect the collection with Marionette
      this.getNextPage();
    })).bind(this)

  },

  mode: "infinite",

  url: "https://api.github.com/repos/jashkenas/backbone/issues?state=closed",

  state: {
    pageSize: 5,
    firstPage: 1
  },

  queryParams: {
    page: null,
    per_page: null,
    totalPages: null,
    totalRecords: null,
    sortKey: null,
    order: null
  },

  /*
  // Enabling this will mean parseLinks don't run.
  sync: function(method, model, options) {
    console.log('sync');

    options.contentType = 'application/json'
    options.dataType = 'json'
    Backbone.sync(method, model, options);
  }
  */

});

// VIEWS
App.View = {};
App.View.MyItemView = Mn.ItemView.extend({
  template: '#item-view'
});

App.View.Button = Mn.ItemView.extend({
  template: '#button',
  events: {
    'click .btn': 'loadMore'
  },
  loadMore: function() {
    Backbone.Events.trigger('load');
  }
});

App.View.MyColView = Mn.CollectionView.extend({
  initialize: function() {
    this.listenTo(this.collection.fullCollection, "add", this.newContent);
    this.collection.getFirstPage();
  },

  newContent: function(model, col, req) {
    console.log('FullCollection length:', this.collection.fullCollection.length, 'Collection length', this.collection.length)
  },

  childView: App.View.MyItemView
});

// CONTROLLER
App.Ctrl = {
  index: function() {
    var col = new App.Collection.All();
    var btn = new App.View.Button();
    var colView = new App.View.MyColView({
      collection: col
    });

    App.Rm.get('main').show(colView);
    App.Rm.get('buttonRegion').show(btn);
  }
};

// ROUTER
App.Routr = Mn.AppRouter.extend({
  controller: App.Ctrl,
  appRoutes: {
    '*path': 'index'
  }
});

App.start();

Solution

  • You could base the CollectionView off the full collection, and pass in the paged collection as a separate option:

    App.View.MyColView = Mn.CollectionView.extend({
      initialize: function(options) {
        this.pagedCollection = options.pagedCollection;
        this.pagedCollection.getFirstPage();
    
        this.listenTo(this.collection, "add", this.newContent);
      },
    
      // ...
    }
    
    // Create the view
    var colView = new App.View.MyColView({
      collection: col.fullCollection,
      pagedCollection: col
    });
    

    Forked fiddle