|
| 1 | +carlosalvidrez:pagination |
| 2 | +================= |
| 3 | + |
| 4 | +Meteor v3+ pagination done right |
| 5 | + |
| 6 | +Forked from: Kurounin:Pagination |
| 7 | + |
| 8 | +This package allows you to paginate the subscriptions over meteor's collections. It can be used in a Blaze template or in ReactJS. |
| 9 | + |
| 10 | + |
| 11 | +Features |
| 12 | +-------- |
| 13 | + |
| 14 | ++ **Incremental subscriptions**. Downloads only what is needed, not the entire collection at once. Suitable for large datasets. |
| 15 | ++ **Instant changes propagation**. Any document changes are instantly propagated, thanks to light-weight modifications of subscription mechanism. |
| 16 | ++ **Easy integration**. The package works out of the box. Page changes are triggered by a single reactive dictionary variable. |
| 17 | ++ **Multiple collections per page**. Each Pagination instance runs independently. You can even create multiple paginations for one collection on a single page. |
| 18 | ++ **Bootstrap 3 and 4 compatible navigation template**. Blaze template for a bootstrap 3 and 4 styled paginator. |
| 19 | ++ **Bootstrap 3 and 4 compatible navigation react class**. ReactJS class for a bootstrap 3 and 4 styled paginator. |
| 20 | + |
| 21 | +# Installation |
| 22 | +```meteor add kurounin:pagination``` |
| 23 | + |
| 24 | +**For Blaze paginator install [kurounin:pagination-blaze](https://atmospherejs.com/kurounin/pagination-blaze) package** |
| 25 | +```meteor add kurounin:pagination``` |
| 26 | + |
| 27 | +**For ReactJS paginator in Meteor 1.2 install [kurounin:pagination-reactjs](https://atmospherejs.com/kurounin/pagination-reactjs) package** |
| 28 | +```meteor add kurounin:pagination-reactjs``` |
| 29 | + |
| 30 | +**For ReactJS paginator in Meteor 1.3+ install [react-bootstrap-pagination](https://www.npmjs.com/package/react-bootstrap-pagination) npm package** |
| 31 | +```npm i react-bootstrap-pagination``` |
| 32 | + |
| 33 | +# Usage |
| 34 | + |
| 35 | +In your collections file (e.g. lib/collections.js): |
| 36 | +```js |
| 37 | +MyCollection = new Meteor.Collection('myCollectionName'); |
| 38 | +``` |
| 39 | + |
| 40 | +In your publications file (e.g. server/publications.js): |
| 41 | +```js |
| 42 | +import { publishPagination } from 'meteor/kurounin:pagination'; |
| 43 | +publishPagination(MyCollection); |
| 44 | +``` |
| 45 | + |
| 46 | +Optionally you can provide a set of filters on the server-side or even dynamic filters, which can not be overridden. |
| 47 | +There's also the option of providing a transformation filter function to validate the client filters (e.g. server/publications.js): |
| 48 | +```js |
| 49 | +publishPagination(MyCollection, { |
| 50 | + filters: {is_published: true}, |
| 51 | + dynamic_filters: function () { |
| 52 | + return {user_id: this.userId}; |
| 53 | + }, |
| 54 | + transform_filters: function (filters, options) { |
| 55 | + // called after filters & dynamic_filters |
| 56 | + allowedKeys = ['_id', 'title']; |
| 57 | + |
| 58 | + const modifiedFilters = []; |
| 59 | + |
| 60 | + // filters is an array of the provided filters (client side filters & server side filters) |
| 61 | + for (let i = 0; i < filters.length; i++) { |
| 62 | + modifiedFilters[i] = _.extend( |
| 63 | + _.pick(filters[i], allowedKeys), |
| 64 | + {user_id: this.userId} |
| 65 | + ); |
| 66 | + } |
| 67 | + |
| 68 | + return modifiedFilters; |
| 69 | + }, |
| 70 | + transform_options: function (filters, options) { |
| 71 | + const fields = { name: 1, email: 1 } |
| 72 | + if (Roles.userIsInRole(this.userId, 'admin')) { |
| 73 | + fields.deleted = 1; |
| 74 | + } |
| 75 | + options.fields = _.extend(fields, options.fields); |
| 76 | + return options; |
| 77 | + } |
| 78 | +}); |
| 79 | + |
| 80 | +``` |
| 81 | + |
| 82 | +For Blaze template |
| 83 | +-------------------------------------------------- |
| 84 | +In your template file (e.g. client/views/mylist.html): |
| 85 | +```html |
| 86 | +<template name="myList"> |
| 87 | + <div> |
| 88 | + {{#if isReady}} |
| 89 | + <ul> |
| 90 | + {{#each documents}} |
| 91 | + <li>Document #{{_id}}</li> |
| 92 | + {{/each}} |
| 93 | + </ul> |
| 94 | + {{> defaultBootstrapPaginator pagination=templatePagination limit=10 containerClass="text-center" onClick=clickEvent}} |
| 95 | + {{else}} |
| 96 | + Loading... |
| 97 | + {{/if}} |
| 98 | + </div> |
| 99 | +</template> |
| 100 | +``` |
| 101 | +**[kurounin:pagination-blaze](https://atmospherejs.com/kurounin/pagination-blaze) package is needed for paginator** |
| 102 | + |
| 103 | + |
| 104 | +In your template javascript file (e.g. client/scripts/mylist.js): |
| 105 | +```js |
| 106 | +Template.myList.onCreated(function () { |
| 107 | + this.pagination = new Meteor.Pagination(MyCollection, { |
| 108 | + sort: { |
| 109 | + _id: -1 |
| 110 | + } |
| 111 | + }); |
| 112 | +}); |
| 113 | + |
| 114 | +Template.myList.helpers({ |
| 115 | + isReady: function () { |
| 116 | + return Template.instance().pagination.ready(); |
| 117 | + }, |
| 118 | + templatePagination: function () { |
| 119 | + return Template.instance().pagination; |
| 120 | + }, |
| 121 | + documents: function () { |
| 122 | + return Template.instance().pagination.getPage(); |
| 123 | + }, |
| 124 | + // optional helper used to return a callback that should be executed before changing the page |
| 125 | + clickEvent: function() { |
| 126 | + return function(e, templateInstance, clickedPage) { |
| 127 | + e.preventDefault(); |
| 128 | + console.log('Changing page from ', templateInstance.data.pagination.currentPage(), ' to ', clickedPage); |
| 129 | + }; |
| 130 | + } |
| 131 | +}); |
| 132 | +``` |
| 133 | + |
| 134 | +For ReactJS template |
| 135 | +-------------------------------------------------- |
| 136 | +In your view file (e.g. client/views/mylist.jsx): |
| 137 | +```html |
| 138 | +MyListPage = React.createClass({ |
| 139 | + mixins: [ReactMeteorData], |
| 140 | + |
| 141 | + pagination: new Meteor.Pagination(MyCollection), |
| 142 | + |
| 143 | + getMeteorData: function() { |
| 144 | + return { |
| 145 | + documents: this.pagination.getPage(), |
| 146 | + ready: this.pagination.ready() |
| 147 | + }; |
| 148 | + }, |
| 149 | + |
| 150 | + renderDocument: function(document) { |
| 151 | + return ( |
| 152 | + <li>Document #{document._id} </li> |
| 153 | + ); |
| 154 | + }, |
| 155 | + |
| 156 | + render: function() { |
| 157 | + if (!this.pagination.ready()) { |
| 158 | + return ( |
| 159 | + <div>Loading...</div> |
| 160 | + ); |
| 161 | + } |
| 162 | + |
| 163 | + return ( |
| 164 | + <div> |
| 165 | + <ul> |
| 166 | + {this.data.documents.map(this.renderDocument)} |
| 167 | + </ul> |
| 168 | + <DefaultBootstrapPaginator |
| 169 | + pagination={this.pagination} |
| 170 | + limit={10} |
| 171 | + containerClass="text-center" |
| 172 | + /> |
| 173 | + </div> |
| 174 | + ); |
| 175 | + } |
| 176 | +}); |
| 177 | +``` |
| 178 | +**For Meteor 1.2 [kurounin:pagination-reactjs](https://atmospherejs.com/kurounin/pagination-reactjs) package is needed for paginator** |
| 179 | + |
| 180 | +**For Meteor 1.3+ [react-bootstrap-pagination](https://www.npmjs.com/package/react-bootstrap-pagination) npm package is needed for paginator** |
| 181 | + |
| 182 | + |
| 183 | +# Demo project |
| 184 | +For an example on how this package can be implemented check [the pagination example project](https://github.com/Kurounin/PaginationExample) or [the react pagination example project](https://github.com/Kurounin/PaginationReactExample). |
| 185 | + |
| 186 | +You can also checkout [this example application in React](https://github.com/mgscreativa/kurounin-pagination-react-example) created by [mgscreativa](https://github.com/mgscreativa). |
| 187 | + |
| 188 | + |
| 189 | +# Server Pagination settings available on init |
| 190 | + |
| 191 | +* `name`: set the publication name (defaults to **collection name**; *needs to be unique, to not collide with other publications*) |
| 192 | +* `filters`: provide a set of filters on the server-side, which can not be overridden (defaults to **{}**, meaning no filters) |
| 193 | +* `dynamic_filters`: provide a function which returns additional filters to be applied (**this** is the publication; receives no other parameters) |
| 194 | +* `transform_filters`: provide a function which returns the modified filters object to be applied (**this** is the publication; receives the current **filters** as an array containing the client & server defined filters and **options** as parameters) |
| 195 | +* `transform_options`: provide a function which returns the modified options object to be applied (**this** is the publication; receives the current **filters** as an array containing the client & server defined filters and **options** as parameters) |
| 196 | +* `countInterval`: set the interval in ms at which the subscription count is updated (defaults to **10000**, meaning every 10s) |
| 197 | + |
| 198 | + |
| 199 | +# Client Pagination settings available on init |
| 200 | + |
| 201 | +* `name`: set the subscription name (defaults to **collection name**; *needs to be identical with the server side publication name*) |
| 202 | +* `page`: set the initial page, for example the page parameter from url (defaults to **1**) |
| 203 | +* `perPage`: set the number of documents to be fetched per page (defaults to **10**) |
| 204 | +* `skip`: set the number of documents that should be skipped when fetching a page (defaults to **0**) |
| 205 | +* `filters`: filters to be applied to the subscription (defaults to **{}**, meaning no filters) |
| 206 | +* `fields`: fields to be returned (defaults to **{}**, meaning all fields) |
| 207 | +* `sort`: set the sorting for retrieved documents (defaults to **{_id: -1}**) |
| 208 | +* `reactive`: set the subscription reactivity, allowing to only retrieve the initial results when set to false (defaults to **true**) |
| 209 | +* `debug`: console logs the query and options used when performing the find (defaults to **false**) |
| 210 | +* `connection`: the server connection that will manage this collection. Pass the return value of calling DDP.connect to specify a different server. (defaults to **Meteor.connection**) |
| 211 | + |
| 212 | + |
| 213 | +# Client Pagination available methods |
| 214 | + |
| 215 | +* `currentPage([int])`: get/set the current page |
| 216 | +* `perPage([int])`: get/set the number of documents per page |
| 217 | +* `skip([int])`: get/set the number of documents to skip |
| 218 | +* `filters([Object])`: get/set the current filters |
| 219 | +* `fields([Object])`: get/set the retrieved fields |
| 220 | +* `sort([Object])`: get/set the sorting order |
| 221 | +* `debug([boolean])`: get/set the debug |
| 222 | +* `totalItems()`: get the total number of documents |
| 223 | +* `totalPages()`: get the total number of pages |
| 224 | +* `ready()`: checks if the subscription for the current page is ready |
| 225 | +* `refresh()`: forcefully refreshes the subscription (useful for non-reactive subscriptions) |
| 226 | +* `getPage()`: returns the documents for the current page |
| 227 | + |
| 228 | + |
| 229 | +# Blaze Paginator template |
| 230 | + |
| 231 | +A Blaze template is provided to allow navigation through available pages: |
| 232 | + |
| 233 | +In the template html file add the paginator |
| 234 | +```html |
| 235 | +{{> defaultBootstrapPaginator pagination=templatePagination onClick=clickEvent limit=10 containerClass="text-center"}} |
| 236 | +``` |
| 237 | +Available template parameters are: |
| 238 | +* `pagination`: pagination instance |
| 239 | +* `limit`: the maximum number of page links to display |
| 240 | +* `containerClass`: optional container class for the paginator |
| 241 | +* `paginationClass`: optional class for the *ul* element (defaults to `pagination`) |
| 242 | +* `itemClass`: optional class for the page links elements |
| 243 | +* `wrapLinks`: if set to true page links will be wrapped in *li* elements (defaults to `true`) |
| 244 | +* `onClick`: optional callback to be called when page link is clicked (default callback runs `e.preventDefault()`) |
| 245 | + |
| 246 | + |
| 247 | +# ReactJS Paginator class |
| 248 | + |
| 249 | +A ReactJS class is provided to allow navigation through available pages: |
| 250 | + |
| 251 | +```js |
| 252 | +<DefaultBootstrapPaginator pagination={this.pagination} limit={10} containerClass="text-center" /> |
| 253 | +``` |
| 254 | +Available class properties are: |
| 255 | +* `pagination`: pagination instance |
| 256 | +* `limit`: maximum number of page links to display (defaults to **10**) |
| 257 | +* `containerClass`: optional container class for the paginator |
| 258 | + |
| 259 | + |
| 260 | +### Packages used as inspiration: |
| 261 | + |
| 262 | + * [alethes:pages](https://atmospherejs.com/alethes/pages) for pagination instantiation |
| 263 | + * [aida:pagination](https://atmospherejs.com/aida/pagination) for bootstrap paginator template |
0 commit comments