Most websites offer some form of pagination. There is a limit how many records can be displayed on a single page and breaking the record set up in pages makes a lot of sense. This pagination sample displays 9 well-known paintings per page. There are 3 pages total.
Like the previous examples this one uses Backbone, underscore templating (with changed template token markers), in-page templates (using <script> tags), and a Mock server. The two script templates are named pictures-template and picture-template respectively.
Here is the pagination code:
var Patterns = { // ** namespace pattern namespace: function (name) { // ** single var pattern var parts = name.split("."); var ns = this; // ** iterator pattern for (var i = 0, len = parts.length; i < len; i++) { // ** || idiomT ns[parts[i]] = ns[parts[i]] || {}; ns = ns[parts[i]]; } return ns; } }; // ** namespace pattern // ** revealing module pattern // ** singleton pattern Patterns.namespace("InAction").Pagination = (function () { // ** namespace pattern var Models = {}; var Views = {}; var Routers = {}; // Change template token markers to {{ and }} _.templateSettings = { interpolate: /\{\{(.+?)\}\}/g, evaluate: /\{\{(.+?)\}\}/g }; // ** extend pattern Routers.Router = Backbone.Router.extend({ // ** init pattern initialize: function (options) { this.el = options.el; }, routes: { "": "paginate", ":page": "paginate" }, paginate: function (page) { // ** truthy/falsy idiom var p = page ? parseInt(page, 10) : 1; // ** chaining pattern this.el.html(new Views.Pagination({ page: p }).el); this.el.append(new Views.Pictures({ page: p }).el); this.el.append(new Views.Pagination({ page: p }).el); } }); // ** extend pattern // ** option hash idiom Models.Picture = Backbone.Model.extend({ }); // ** extend pattern // ** option hash idiom Models.Pictures = Backbone.Collection.extend({ model: Models.Picture, url: "pagination" }); // ** extend pattern // ** option hash idiom Views.Pictures = Backbone.View.extend({ tagName: "ul", className: "thumbnails", // ** init pattern initialize: function (options) { this.page = options.page; this.collection = new Models.Pictures(); this.collection.bind("reset", this.render, this); this.collection.fetch({ data: { page: this.page } }); }, render: function () { // ** iterator pattern this.collection.each(function (picture) { var view = new Views.Picture({ model: picture }); this.$el.append(view.render().el); }, this); return this; } }); // ** extend pattern // ** option hash idiom Views.Picture = Backbone.View.extend({ tagName: "li", template: _.template($('#picture-template').html()), render: function () { this.$el.html(this.template(this.model.toJSON())); return this; } }); // ** extend pattern // ** option hash idiom Views.Pagination = Backbone.View.extend({ tagName: "div", // this is default className: "pagination pagination-centered", // ** init pattern initialize: function (options) { this.page = options.page; this.render(); }, render: function () { var pageCount = Math.ceil(pictures.length / 9); this.$el.css("padding-right", "100px"); this.$el.append("
The idioms and patterns used in this example are:
Each page makes a mocked Ajax server call and gets a number of pictures returned. Depending on how users use the app, you may consider caching the pictures already returned to the client. This could be implemented using the Lazy Load pattern. To keep things simple this is not implemented in this example but wouldn't be hard to add.