Skip to content

Instantly share code, notes, and snippets.

@bfagundez
Created March 18, 2013 22:14
Show Gist options
  • Save bfagundez/5191302 to your computer and use it in GitHub Desktop.
Save bfagundez/5191302 to your computer and use it in GitHub Desktop.
A CodePen by martian. Backbone Paginate+Filter mixin - Adds a mixin to a Backbone view to paginate and filter a collection. Requires Cocktail.
<script type="text/html" id="template-mappings_grid_view">
<span class="the-number"></span>
<table class="table table-striped table-bordered table-condensed">
<thead>
<tr>
<% _.each(colDefinition, function(col) { %>
<td><%= col.name %></td>
<% }); %>
</tr>
</thead>
<tbody>
<% _.each(record_list, function(row) { %>
<tr>
<% _.each(colDefinition, function(col) { %>
<td>
<%= row.get(col.key) %>
</td>
<% }); %>
</tr>
<% }); %>
</tbody>
</table>
</script>
<script type="text/html" id="template-pagination">
<div class="pagination pagination-mini">
<ul class="pull-right">
<li class="<%= current_page == 1 ? 'disabled' : '' %> previous"><a href="#">Prev</a></li>
<% for(var i = 1; i <= total_pages; i++) { %>
<li class="<%= i == current_page ? 'active' : '' %> goto_page" data-pagenumber="<%= i %>"><a href="#"><%= i %></a></li>
<% } %>
<li class="<%= current_page == total_pages ? 'disabled' : '' %> next"><a href="#">Next</a></li>
</ul>
</div>
<div class="pull-right" style="margin:5px 0;clear:both;"><small><strong><%= total_records %></strong> records, showing from <strong><%= (current_page - 1 ) * records_per_page %></strong> to <strong><%= total_records > current_page * records_per_page ? current_page * records_per_page:total_records %></strong>, page <strong><%= current_page %></strong></small></div>
</script>
<div class="span8">
<div id="the_grid"></div>
</div>
// Defines the structure of the records
MappingRecord = Backbone.Model.extend({});
MappingCollection = Backbone.Collection.extend({model: MappingRecord });
var MappingsGridView = Backbone.View.extend({
template: $('#template-mappings_grid_view').html(),
initialize: function(){
// This is needed for the PAGINATED MIXIN!
// instead of calling this.render, this.refreshPage must be called.
this.listenTo(this.collection, 'add', this.refreshPage);
this.listenTo(this.collection, 'remove', this.refreshPage);
this.$el = this.options.$el;
// add a container, so we are able to refresh just records
this.container_id = _.uniqueId('grid_container');
this.$el.append('<div id="'+this.container_id +'"></div>');
this.$container = $('#'+this.container_id);
},
colDefinition: [
{ name: 'A', key: 'record_a'},
{ name: 'B', key: 'record_b' }
],
render: function(){
this.$container.html(_.template(this.template, { 'record_list' : this.recordlist , 'colDefinition': this.colDefinition}));
this.delegateEvents();
return this;
}
});
var PaginateMixin = {
initialize: function() {
this.currentPage = 0;
this.recordsPerPage = this.options.recordsPerPage ? this.options.recordsPerPage : 20;
this.getPageItems(this.currentPage);
this.fields_to_filter = this.options.fields_to_filter ? this.options.fields_to_filter : ['name'];
_.each(this.collection.models, function(rec){
rec.set('visible',true);
});
this.paginator_id = _.uniqueId('paginator');
this.filter_id = _.uniqueId('filter');
this.$el.prepend('<div class="row"> \
<div class="span2 pull-left" style="padding-top:15px"><div class="input-prepend"><span class="add-on">Filter</span><input class="span2 filter_grid" type="text" id="'+this.filter_id+'" ></div></div> \
<div class="span2 pull-left"></div>\
<div class="span4 pull-right"><div id="'+this.paginator_id+'"></div></div> \
</div>');
this.subcollection = this.collection;
},
events: {
'keyup .filter_grid' : 'filterCollection',
'click .previous': 'goToPreviousPage',
'click .next': 'goToNextPage',
'click .goto_page' : 'goToPageNumber'
},
goToPageNumber: function(ev){
this.goToPage($(ev.target).text() - 1);
},
render: function() {
var numberOfPages = this.numberOfPages();
$('#'+this.paginator_id).html(_.template($('#template-pagination').html(),{ total_pages : numberOfPages , current_page: this.currentPage + 1, total_records: this.subcollection.length, records_per_page: this.recordsPerPage }));
return this;
},
goToPage: function(page) {
var numberOfPages = this.numberOfPages();
numberOfPages > 0 ? this.currentPage = Math.min(Math.max(page, 0), numberOfPages - 1) : this.currentPage = 0;
this.getPageItems(page);
this.render();
return this.currentPage;
},
filterCollection: function(event){
var search_string = event ? $(event.currentTarget).val() : '';
if(search_string != ''){
var self = this;
var keys = this.fields_to_filter;
_.each(this.collection.models, function(rec){
rec.set('visible',false);
_.each(keys, function(key){
console.log(key,rec.get(key),rec);
if(rec.get(key).replace(/\s+/g, '').toLowerCase().indexOf(search_string.replace(/\s+/g, '').toLowerCase()) > -1 ){
rec.set('visible',true);
}
});
});
} else {
var self = this;
_.each(this.collection.models, function(rec){
rec.set('visible',true);
});
}
this.getPageItems();
this.render();
},
refreshPagination: function(){
var numberOfPages = this.numberOfPages();
$($(this.$el).find('.pagination')[0]).html(_.template($('#template-pagination').html(),{ total_pages : numberOfPages , current_page: this.currentPage + 1 , total_records: this.subcollection.length, records_per_page: this.recordsPerPage }));
},
refreshPage: function(){
this.goToPage(this.currentPage);
},
goToNextPage: function() {
return this.goToPage(this.currentPage + 1);
},
goToPreviousPage: function() {
return this.goToPage(this.currentPage - 1);
},
getPageItems: function(page) {
page == null ? page = this.currentPage : '' ;
var start = this.recordsPerPage * page;
var end = this.recordsPerPage * page + this.recordsPerPage;
var subcollection = this.collection.where({ 'visible':true });
end > subcollection.length ? end = subcollection.length : ''
this.recordlist = [];
for(var i = start; i < end; i++) {
this.recordlist.push(subcollection[i]);
}
// go back 1 page if this recordlist is empty
this.recordlist.length == 0 && subcollection.length > 0 ? this.goToPage(0) : '';
this.subcollection = subcollection;
},
numberOfPages: function() {
return Math.ceil(this.subcollection.length / this.recordsPerPage);
}
}
// Apply the mixin to the view
Cocktail.mixin(MappingsGridView, PaginateMixin);
huge_collection = new MappingCollection;
for(var i = 0; i < 98; i++) {
huge_collection.add({ 'record_a' : 'arec'+i, 'record_b' : 'brec'+i , 'visible': true });
}
grid_view = new MappingsGridView({'collection':huge_collection, $el: $('#the_grid') , fields_to_filter : ['record_a','record_b']});
grid_view.render();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment