3

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;
});
Dileep Paul
  • 167
  • 3
  • 17

2 Answers2

2

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;
});
Dileep Paul
  • 167
  • 3
  • 17
1

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.

david_i_smith
  • 228
  • 3
  • 12
  • Thanks smith, but do you have suggestion if want to fetch collection inside the view itself? – Dileep Paul Nov 25 '14 at 04:55
  • 2
    You could still fetch models from the master collection (GroupCollection). It's just that you would be adding the relevant models from each fetch to a temporary collection. The temporary collection would start out as empty and be added to with each new "pull" for data. Make sense? Having said this I'd still recommend creating a controller to manage the data requests and view creation. Makes for a cleaner separation of concerns IMO. – david_i_smith Nov 25 '14 at 18:15