Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save thorn/2717862 to your computer and use it in GitHub Desktop.
Save thorn/2717862 to your computer and use it in GitHub Desktop.
backbone pagination with coffeescript
# coffeescript rules
# Pagination is sticked with model
#
# Server should response in that way:
# {
# articles: [{category_id:null, id:308,…}, {category_id:null, id:307,…}, {category_id:null, id:306,…},…]
# pagination: {total:34, page:2, per_page:15, cat_id:-1, source_id:-1}
# }
# To achieve this controller should look like (using will_paginate gem):
# per_page = params[:per_page].to_i || 15
# @articles = Article.scoped.page(params[:page]).per_page(@per_page)
# @pagination = { total: @articles.count, page: @articles.current_page, per_page: @per_page}
#
# respond_to do |format|
# format.html
# format.json { render json: {articles: @articles, pagination: @pagination}}
# end
class ArticlesCollection extends Backbone.Collection
model: ArticlesModel
initialize: (options) =>
@init_pagination(options)
init_pagination: (options) =>
@page = options.pagination.page
@perPage = options.pagination.per_page
@total = options.pagination.total
# ovrride default function to parse server response
# response consists of {articles:{...}, pagination{...}}
parse: (resp) =>
@init_pagination(resp)
return resp.articles
url: =>
@baseUrl + '?' + $.param({page: @page, perPage: @perPage})
pageInfo: =>
info =
total: @total
page: @page
perPage: @perPage
pages: Math.ceil(@total / @perPage)
prev: false
next: false
pagination: @windowed_page_number()
max = Math.min(@total, @page * @perPage)
max = @total if @total is @pages * @perPage
info.range = [(@page - 1) * @perPage + 1, max]
info.prev = @page - 1 if @page > 1
info.next = @page + 1 if @page < info.pages
info
nextPage: =>
return false if !@pageInfo().next
@page = @page + 1
return @fetch()
previousPage: =>
return false if !@pageInfo().prev
@page = @page - 1
return @fetch()
gotoPage: (page) =>
@page = page
return @fetch()
# Function taken from will_paginate guts
# returns array that look like [1,2,"...",5,6,7,8,"...", 19,20]
# ^ ^ ^
# outer_window inner_window outer_window
windowed_page_number: =>
inner_window = 4
outer_window = 1
total_pages = Math.ceil(context.total / context.perPage)
window_from = context.page - inner_window
window_to = context.page + inner_window
if window_to > total_pages
window_from -= window_to - total_pages
window_to = total_pages
if window_from < 1
window_to += 1 - window_from
window_from = 1
window_to = total_pages if window_to > total_pages
middle = [window_from..window_to]
if outer_window + 3 < middle[0]
left = [1..(outer_window + 1)]
left.push "..."
else
left = [1...middle[0]]
if (total_pages - outer_window - 2) > middle[middle.length - 1]
right = [(total_pages - outer_window)..total_pages]
right.unshift "..."
else
right_start = Math.min(middle[middle.length - 1] + 1, total_pages)
right = [right_start..total_pages]
right = [] if right_start is total_pages
return left.concat(middle.concat(right))
class ArticlesIndexView extends Backbone.View
events:
# binds for pagination
'click a.previous_page' : 'previous'
'click a.next_page' : 'next'
'click a.set_page' : 'goto_page'
initialize: () ->
@collection.on 'reset', @render
render: =>
# just stub for rendering
$(@el).html('')
@will_paginate()
return this
will_paginate: =>
if @collection.pageInfo().pages > 1
# pagination template is listed below
$(@el).append JST["backbone/templates/articles/pagination"](page_info: @collection.pageInfo())
previous: =>
@collection.previousPage()
return false
next: =>
@collection.nextPage()
return false
goto_page: (ev) =>
@collection.gotoPage parseInt($(ev.target).text())
return false
/ pagination view written using haml_coffee_assets gem
/ it looks much cleaner than templates like ejs
.pagination
- if @page_info.pages > 1
- if @page_info.prev
%a.previous_page{href: "#"} <
- else
%span.previous_page.disabled <
- for page in @page_info.pagination
- if page is "..."
%span.gap ...
- else if page is @page_info.page
%em.current= page
- else
%a.set_page{href: "#"}= page
- if @page_info.next
%a.next_page{href: "#"} >
- else
%span.next_page.disabled >
@Sparkmasterflex
Copy link

This was exactly what I needed. Thanks!

Though I'm not sure if I'm missing something but in ArticlesCollection#windowed_page_number does context.total, context.page and context.perPage need to actually be this.?

I kept getting an error because context was not defined

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment