I recently had to create some pagination for a backbone.js project I’ve been working on. What I created has been working quite well but was not 100% happy with what I did. Since I had a week off I figured I’d rewrite it as a mixin and clean up the approach. Will have to work it back into the project somehow but that is something to worry about later.
Let’s just jump right in there. Some caveats: I am sure there is probably a better approach to some of the code, so please give some guidance on how it should be improved. This code assumes that all the data is already loaded into the collection. The set of data I was working with had a record count of about 28,000 items. I’ve gone back and both on if having that much data loaded is a good or bad thing. Of all the articles I’ve read there doesn’t seem to be a consensus.
The folder structure I am using is:
The JSON structure I am dealing with:
The model, nothing too special going on here:
The collection, again, is a pretty basic set up. I’ve set to model to map to App.models.Tag, our url to point to tags_all.php and overridden the parse method to return a cleaned up tags array.
The last line _.extend(collections.Tags.prototype, pagination); is where we mixin in our Pagination module(?: not sure what its proper name is actually. Module, Class?).
Next up is the Pagination mixin code, have a read of it and I’ll comment after the code.
Most of the code is pretty self-explanatory, so I won’t dig into every line. There are some methods you will see in the code, setSort and _sort, that are actually not in use for this discussion but will follow up on them in another post.
The first four methods are the ones that get triggered to start the ball rolling on the pagination. Each of them call the pager method.
The page method makes a backup copy of the models the first pass through. Resets models with said backup. Ignore the sort for this post. And lastly we pass in the start and stop points into the Array slice method, which we in turn pass to the Backbone.js reset method. This will trigger a reset event and any view that is watching it will execute.
The last two methods to concern yourself with is the info and setPagination methods. The info method does some base variable set up that will be used in views that need that info, our pagination view for-instance. The setPagination method is called by info and at this point I must add two things. The first is that I more or less borrowed the code from a PHP pagination script and can’t find it again, otherwise I’d give credit. The second is that the purpose of setPagination is to allow for custom pagination structure and I was not clear I how I should make this more straight forward. Any suggestions would be great.
So, what does setPagination do? Basically it returns an array of what pages you want in your pagination — this will become a bit clearer what you see the pagination view below/in action, but let me try to explain. In the code that is there, if we are on page 8 of our recordset, the pages that show will look something like this: 5 6 7 8 9 10 11. But you are not limited to that structure. In the project I will be merging this into, it will have a structure like, assuming I am on page 8 again: 1-5 6 7 8 9 10 11-15.
Hopefully that is clear.
Next two up are the pagination view and template/index page themselves. The final structure will look something like: “FirstPrevious567 8 91011NextLast Show 20 | 50 | 100 141 – 160 of 28091 shown”. Again, everything should be pretty self-explanatory, each method is named to do what it is supposed to do.
I am using underscore.js’ template function. Only real thing to note is the _.each loop. This is where the “pages”, e.g. “5 6 7 8 9 10 11“, will get parsed out.
This last bit is the view that helps parses out the tags.
Like anything else, there are a hundred ways to do things and this is just one. My example goes off the assumption that all the data is available but I am sure it can be re-written to only fetch a certain number of records from the server on an as needed basis.
What would you do differently? Did you see anything wrong with my implementation?