Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

includes the ability to persist additional query params #7

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
17 changes: 17 additions & 0 deletions README.md
Expand Up @@ -55,17 +55,34 @@ app.get('/posts', function(req, res, next) {
});
```

optionally, you can control the paging size for mongoose using the following:

```
Post.find().paginate({ page: req.query.page, perPage: 5 }, callback);
```

Then in the posts/index template, you could include the html generated from posts.pagination.render().
E.g. in Jade, this might look like:
```
!= posts.pagination.render({ baseUrl: '/posts })
```
## Persisting Additional QueryString Parameters
For cases where you might need to persist other values while paging, you can pass the req.query object forward:
```
Post.find().paginate({ page: req.query.page, query: req.query }, function(err, posts){
...
});
```

## Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [grunt](https://github.com/cowboy/grunt).

## Release History

### 0.1.2

- ADDITION: Ability to persist additional querystring params.

### 0.1.1

- FIX: Queries with 0 results caused an invalid skip value to throw an error.
Expand Down
96 changes: 48 additions & 48 deletions lib/mongoose-paginate.js
Expand Up @@ -3,64 +3,64 @@
* A Mongoose Query paginate function that can be patched onto `Mongoose.Query`.
*/

module.exports = function(paginate) {
return function(options, callback) {
var query = this;
var model = query.model;
module.exports = function (paginate) {
return function (options, callback) {
var query = this;
var model = query.model;

model.count(query._conditions, function(err, count) {
if (err) {
return callback(err);
}
model.count(query._conditions, function (err, count) {
if (err) {
return callback(err);
}

// Return early if count is 0 to avoid the extra MongoDB query.
if (count === 0) {
return process.nextTick(preCallbackHandler);
}
// Return early if count is 0 to avoid the extra MongoDB query.
if (count === 0) {
return process.nextTick(preCallbackHandler);
}

var perPage = options.perPage || 10;
var page = parseInt(options.page, 10) || 1;
var last = Math.ceil(count / perPage);
var perPage = options.perPage || 10;
var page = parseInt(options.page, 10) || 1;
var last = Math.ceil(count / perPage);

// Clamp the page to positive numbers within the range.
if (page < 0) {
page = 1;
}
if (page > last) {
page = last;
}
// Clamp the page to positive numbers within the range.
if (page < 0) {
page = 1;
}
if (page > last) {
page = last;
}

var skip = (page - 1) * perPage;
var skip = (page - 1) * perPage;

query
query
.skip(skip)
.limit(perPage);

/*
// @NOTE: Ideally we could support query chaining,
// but it doesn't seem possible unless we tap into the exec/execFind functions too.
if (typeof callback === 'undefined') {
return query;
}
else { ... }
*/
query.exec(preCallbackHandler);
/*
// @NOTE: Ideally we could support query chaining,
// but it doesn't seem possible unless we tap into the exec/execFind functions too.
if (typeof callback === 'undefined') {
return query;
}
else { ... }
*/
query.exec(preCallbackHandler);

/**
* The preCallbackHandler adds pagination to the models collection and then calls back.
* Used by both query callback and if we are returning early due to a 0 count.
*/
function preCallbackHandler(err, models) {
if (err) {
return callback(err);
}
models = models || [];
/**
* The preCallbackHandler adds pagination to the models collection and then calls back.
* Used by both query callback and if we are returning early due to a 0 count.
*/
function preCallbackHandler(err, models) {
if (err) {
return callback(err);
}
models = models || [];

// Add the pagination property to the returned array of models.
models.pagination = paginate(count, perPage, page);
// Add the pagination property to the returned array of models.
models.pagination = paginate(count, perPage, page, options.query);

callback(null, models);
}
});
};
callback(null, models);
}
});
};
};
22 changes: 19 additions & 3 deletions lib/paginate.js
Expand Up @@ -36,7 +36,7 @@ module.exports = function(options) {
return 0;
}

function paginate(itemCount, itemsPerPage, current) {
function paginate(itemCount, itemsPerPage, current, query) {
// Sane defaults.
itemsPerPage = itemsPerPage || 10;
current = current || 1;
Expand Down Expand Up @@ -80,7 +80,8 @@ module.exports = function(options) {
totalPages: last,
left: left,
right: right,
window: window
window: window,
query: query
});

// Add a reference to previous/next pages,
Expand All @@ -97,6 +98,20 @@ module.exports = function(options) {
}
});

if(query){
var params = [];
for(var q in query){
if(q !== 'page'){
params.push(q + '=' + query[q]);
}
}

query = '';
if(params.length > 0){
query = '&' + params.join('&');
}
}

return {
pages: pages,
render: function render(options) {
Expand All @@ -109,7 +124,8 @@ module.exports = function(options) {
var html = fn({
baseUrl: options.baseUrl || '/',
pages: pages,
currentPage: currentPage
currentPage: currentPage,
query: query
});
return html;
}
Expand Down
8 changes: 6 additions & 2 deletions package.json
@@ -1,7 +1,7 @@
{
"name": "paginate",
"description": "Pagination. Especially useful with Mongoose + Express/Jade.",
"version": "0.1.1",
"version": "0.1.3",
"homepage": "https://github.com/tonymilne/paginate",
"author": {
"name": "Tony Milne",
Expand Down Expand Up @@ -39,5 +39,9 @@
"dependencies": {
"underscore": "~1.4.1",
"jade": "~0.27.6"
}
},
"readme": "# paginate\n\nPagination. Especially useful with Mongoose + Express/Jade.\n\n## Getting Started\nInstall the module with: `npm install paginate`\n\nThe paginate plugin returns a function that accepts an options object.\nCall this to get access to the module functionality itself. E.g:\n\n```javascript\nvar paginate = require('paginate')({\n\t// options go here...\n});\n```\n\n## Documentation\n\n_(Coming soon)_\n\n## Examples\n\n### Basic (non Mongoose) usage\n\n```javascript\nvar paginate = require('paginate')();\nvar data = new Array(95);\n\nvar PER_PAGE = 10;\nvar currentPage = 6;\n\nvar pagination = paginate.page(data.length, PER_PAGE, currentPage);\nvar html = pagination.render({ baseUrl: '/example' });\n```\n\n### Mongoose + Express usage\n\n```\nvar mongoose = require('mongoose');\nvar paginate = require('paginate')({\n\tmongoose: mongoose\n});\n\n// @NOTE: Assuming a post model has been created and registered...\nvar Post = mongoose.model('posts');\n\n// An express route action:\napp.get('/posts', function(req, res, next) {\n\tPost.find()\n\t.paginate({ page: req.query.page }, function(err, posts) {\n\t\tres.render('posts/index', {\n\t\t\tposts: posts\n\t\t})\n\t});\n});\n```\n\nThen in the posts/index template, you could include the html generated from posts.pagination.render().\nE.g. in Jade, this might look like:\n```\n!= posts.pagination.render({ baseUrl: '/posts })\n```\n\n## Contributing\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [grunt](https://github.com/cowboy/grunt).\n\n## Release History\n\n### 0.1.1\n\n- FIX: Queries with 0 results caused an invalid skip value to throw an error.\n- FIX: Typo in the readme params to query.\n\n## License\nCopyright (c) 2012 Tony Milne\nLicensed under the MIT license.\n",
"readmeFilename": "README.md",
"_id": "paginate@0.1.1",
"_from": "paginate@"
}
4 changes: 2 additions & 2 deletions views/next.jade
@@ -1,2 +1,2 @@
li
a(href='#{baseUrl}?page=#{currentPage.nextPage.page}') Next &rsaquo;
li.next
a(href='#{baseUrl}?page=#{currentPage.nextPage.page}#{query}') Next &rsaquo;
8 changes: 4 additions & 4 deletions views/page.jade
@@ -1,5 +1,5 @@
li
if page.isCurrent
a.active #{page.page}
else
a(href='#{baseUrl}?page=#{page.page}') #{page.page}
if page.isCurrent
a.active #{page.page}
else
a(href='#{baseUrl}?page=#{page.page}#{query}') #{page.page}
4 changes: 2 additions & 2 deletions views/previous.jade
@@ -1,2 +1,2 @@
li
a(href='#{baseUrl}?page=#{currentPage.previousPage.page}') &lsaquo; Previous
li.previous
a(href='#{baseUrl}?page=#{currentPage.previousPage.page}#{query}') &lsaquo; Previous