How can we do paging with backbone marionette composite view?

3.6k Views Asked by At

I am new to backbone and marionette. Now i m trying to implement paging with compositeview of marionettejs. Below is my code, what happens here that when a new fetch is done through my custom pager, existing data is getting replaced by new set of data instead of appending. Please help me to overcome this! Thanks in advance.

 define(['text!/Templates/projects/_GroupItem.html', 'collections/projects/groups'], function (ProjectGroupsTmpl, GroupCollection) {
    var GroupItemView = Backbone.Marionette.ItemView.extend({
        tagName: 'li',
        template: _.template(ProjectGroupsTmpl) 
    });
    var CompositeView = Backbone.Marionette.CompositeView.extend({
        template: _.template("<ul id='ulgroups' ></ul>"),
        itemView: GroupItemView,
        itemViewContainer: '#ulgroups',
        initialize: function (params) {
            this.isLoading = false; 
            this.ProjectID = params.id;
            this.collection = new GroupCollection();
            this.getData();
            var self = this;
            $(window).scroll(function () {
                self.checkScroll();
            });
        },
        getData: function () { 
            var that = this;
            this.isLoading = true;
            this.collection.fetch({ 
                data: { ProjectID: this.ProjectID },
                success: function (collection, response, options) { 
                    that.isLoading = false;
                }
            });
        },
        checkScroll: function () { 
            var triggerPoint = 100; // 100px from the bottom 
            if (!this.isLoading && $(window).scrollTop() + $(window).height() + triggerPoint > $(document).height()) { 
                this.collection.page += 1; // Load next page 
                this.getData();
            }
        },
        appendHtml: function (collectionView, itemView, index) {            
            $(this.itemViewContainer).append(itemView.el);
        }
    });
    return CompositeView;
});
2

There are 2 best solutions below

0
On BEST ANSWER

I have used backbone.paginator to resolve above issue and it works well. Below are the new code used for that.

Collection:

   define([
  'jquery',
  'underscore',
  'backbone',
  'helper',
  'paginator'
], function ($, _, Backbone) {
    var Groups = Backbone.PageableCollection.extend({
        url: 'projects/_groups',
        mode: "infinite",
        state: {
            pageSize: null 
        },
        queryParams: {
            totalPages: null,
            totalRecords: null 
        }
    });
    return Groups;
});

Marionette CompositeView:

define(['text!/Templates/projects/_GroupItem.html', 'collections/projects/groups'], function (ProjectGroupsTmpl, GroupCollection) {
    var GroupItemView = Backbone.Marionette.ItemView.extend({
        tagName: 'li',
        template: _.template(ProjectGroupsTmpl)
    });
    var CompositeView = Backbone.Marionette.CompositeView.extend({
        template: _.template("<ul id='ulgroups' ></ul>"),
        itemView: GroupItemView,
        itemViewContainer: '#ulgroups',
        initialize: function (params) {
            this.isLoading = false;
            this.ProjectID = params.id;
            this.grpcollection = new GroupCollection([], {
                queryParams: {
                    ProjectID: params.id
                }
            });
            this.collection = this.grpcollection.fullCollection;
            this.getData();
            var self = this;
            $(window).scroll(function () {
                self.checkScroll();
            });
        },
        getData: function () {
            var that = this;
            this.isLoading = true;
            this.grpcollection.fetch({
                success: function (collection, response, options) {
                    if (response.length > 0) {
                        that.isLoading = false;
                    }
                }
            });
        },
        getNextPage: function () {
            var that = this;
            this.isLoading = true;
            this.grpcollection.getNextPage({
                success: function (collection, response, options) {
                    if (response.length > 0) {
                        that.isLoading = false;
                    }
                }
            });
        },
        checkScroll: function () {
            var triggerPoint = 100; // 100px from the bottom 
            if (!this.isLoading && $(window).scrollTop() + $(window).height() + triggerPoint > $(document).height()) {
                this.getNextPage();
            }
        },
        appendHtml: function (collectionView, itemView, index) {
            $(this.itemViewContainer).append(itemView.el);
        }
    });
    return CompositeView;
});
2
On

I solved a similar problem recently by creating a temporary collection to hold the models for each paginated request. My setup was slightly different to yours, however, in that I created a Marionette controller to negotiate between the data and the view. A "show" method on the controller handled the initial data request and a "showMore" method handled subsequent requests. Here is basically what I did:

(function ($, _, Backbone, Marionette) {
    var carData = [
        {
            make: 'Audi',
            model: 'A4',
            year: '1994'
        },
        {
            make: 'BMW',
            model: '3 Series',
            year: '1975'
        },
        {
            make: 'Chevrolet',
            model: 'Cruze',
            year: '2008'
        },
        {
            make: 'Daimler',
            model: 'Six',
            year: '1994'
        },
        {
            make: 'Fiat',
            model: '500X',
            year: '2015'
        },
        {
            make: 'Honda',
            model: 'Civic',
            year: '1972'
        },
        {
            make: 'Kia',
            model: 'Optima',
            year: '2015'
        },
        {
            make: 'Lada',
            model: 'Priora',
            year: '2007'
        },
        {
            make: 'Mitusbishi',
            model: 'Lancer',
            year: '1973'
        },
        {
            make: 'Nissan',
            model: 'Pathfinder',
            year: '1995'
        }
    ];
    var Car = Backbone.Model.extend({
        defaults: {
            make: '',
            model: '',
            year: ''
        }
    });
    var Cars = Backbone.Collection.extend({
        model: Car,
        rows: 3,
        page: 0
    });
    var CarView = Marionette.ItemView.extend({
        tagName: 'tr',
        template: '#row-template'
    });
    var CarsView = Marionette.CompositeView.extend({
        childView: CarView,
        childViewContainer: 'tbody',
        template: '#table-template',
        triggers: {
            'click button': 'showMore'
        }
    });
    var CarController = Marionette.Controller.extend({
        initialize: function (options) {
            this.collection = options.collection;
        },
        show: function () {
            var cars = this.getData(this.collection.page);
            var carsView = new CarsView({
                collection: new Backbone.Collection(cars)
            });
            this.listenTo(carsView, 'showMore', this.showMore);
            app.carsRegion.show(carsView);
        },
        showMore: function (options) {
            var cars = this.getData(++this.collection.page);
            options.collection.add(cars);
        },
        getData: function (page) {
            var rows = this.collection.rows;
            var start = page * rows;
            var end = start + rows;
            return this.collection.slice(start, end);

        }
    });
    var app = new Marionette.Application();
    var cars = new Cars(carData);
    var carController = new CarController({
        collection: cars
    });
    app.addRegions({
        carsRegion: '#cars-region'
    });
    app.addInitializer(function () {
        carController.show();
    });
    app.start();
}(jQuery, _, Backbone, Marionette));

This is also available as a JSFiddle.