Last active
December 12, 2015 04:48
-
-
Save jkresner/4716553 to your computer and use it in GitHub Desktop.
Filter + PagingCollection Improved. A Filtering collection is a collection that has 2 views of it's models. (1) The original set of models and a filtered view using some custom filtering logic defined in the child collection of the base FilteringCollection class. A PagingCollection inherits from FilteringCollection and can keep track of and retu…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" FilteringCollection | |
(1) Holds an original AND a filtered view of it's models | |
(2) Can sort filtered models on any arbitrary attribute | |
- sort can be invoked multiple times with different attributes to get | |
sorted by A then B """ | |
class FilteringCollection extends Backbone.Collection | |
# Use coffee's constructor function so we can enforce initialization code + | |
# let the child class use the standard Backbone initialize function to | |
# execute it's own initialization code | |
constructor: -> | |
# when the collection is reset, we need to set the filtered models | |
@on 'reset', @reset_filteredmodels, @ | |
# Call Backbone.Collection ctor so backbone calls initialize function | |
Backbone.Collection::constructor.apply(@, arguments) | |
reset_filteredmodels: -> | |
@filteredmodels = @models | |
# We separate sorting from setting the filtered models & firing the sort event | |
# This give flexibility to use sort in combination with filter below without | |
# firing multiple events & causing views listening to both to render twice | |
sort_filteredmodels: (attr, direction, type) -> | |
@filteredmodels = @_sort attr, direction, type | |
@trigger 'sort' | |
# Implementation of bi-directional sort on any attribute of the models | |
_sort: (attr, direction, type) -> | |
if ! attr? then return @filteredmodels | |
if direction is 'up' || !direction? then @comparator = (m) -> m.get(attr) | |
else if type is 'String' then @comparator = (m) -> reversestring(m, attr) | |
else then @comparator = (m) -> -1 * m.get(attr) | |
_.sortBy @filteredmodels, @comparator | |
# Combine sort + filter & only trigger one event. We could still access _sort | |
# & _filter separately if we want ... (f) = some custom object | |
filter_filteredmodels: (f) -> | |
@filteredmodels = @_filter f | |
# Sort is an object like { attr: 'Name', direction: 'up', type: 'String' } | |
if f? && f.sort? | |
@filteredmodels = @_sort f.sort.attr, f.sort.direction, f.sort.type | |
@trigger 'filter' | |
_filter: (f) -> | |
console.log 'override _filter in child class' | |
@models # return non-implemented filter view of the models | |
""" PagingAndFilterCollection | |
(1) Can keep track of current page & return it using fetchpage() """ | |
class PagingAndFilterCollection extends FilteringCollection | |
pagesize: 25 # can override in the child collection | |
# Again wire into coffee ctor to make sure we hook up events and still let | |
# child class use Backbone.Collection.initialize for it's own init code | |
constructor: (args) -> | |
# Called FilteringCollection ctor with calls Backbone.Collection ctor | |
FilteringCollection::constructor.apply(@, arguments) | |
# If we filter or sort the collection we go back to page one as the | |
# number of pages will most likely have changed | |
@on 'filter sort', @resetpaging, @ | |
# Override base reset_filteredmodels and combine it with reset paging | |
reset_filteredmodels: -> | |
FilteringCollection::reset_filteredmodels.apply(@, arguments) | |
@resetpaging() | |
# Recalculate our total pages and reset our current page back to 1 | |
resetpaging: -> | |
@totalpages = Math.ceil(@filteredmodels.length / @pagesize) | |
@currentpage = if @totalpages > 0 then 1 else 0 | |
# Move to next, previous or a specific page number | |
setpage: (page) -> | |
if page is '»' && @currentpage < @totalpages then @setpage @currentpage+1 | |
else if page is '«' && @currentpage > 1 then @setpage @currentpage-1 | |
else | |
page = parseInt page | |
if page <= @totalpages && page > 0 | |
@currentpage = page | |
@trigger('page') | |
# Return the models in the current page | |
fetchpage: -> | |
start = @pagesize * (@currentpage - 1) | |
_.first _.rest(@filteredmodels, start), @pagesize | |
# http://stackoverflow.com/questions/5636812/sorting-strings-in-reverse-order-with-backbone-js | |
reversestring = (m, attr) -> | |
if ! m.get(attr)? then return '' | |
String.fromCharCode.apply String, _.map(m.get(attr).split(""), (c) -> 0xffff - c.charCodeAt() ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Tea extends Backbone.Model | |
class Teas extends FilteringAndPagingCollection | |
model: Tea | |
pagesize: 10 | |
url: '/api/teas' | |
initialize: (args) -> | |
console.log 'can do initialize code here & base initialize code still gets called' | |
""" f might look like | |
{ | |
origin: 'China', | |
type: ['Green','Oolong'], | |
search: 'Smokey', | |
sort: { attr: 'origin', direction: 'up', type: 'String' } | |
} | |
""" | |
_filter: (f) -> | |
r = @models | |
if f? | |
if @hasSelection f.origin | |
r = _.filter r, (m) => f.location is m.get('origin') | |
if @hasSelection f.type | |
r = _.filter r, (m) => _.contains f.type, m.get('type') | |
if @hasSelection f.search | |
pattern = new RegExp f.search, "gi" | |
r = _.filter r, (m) -> | |
pattern.test(m.get("name")) || | |
pattern.test(m.get("description")) | |
r |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment