问题
I am working on a blogging application (click the link to see the GitHub repo) with Express, EJS and MongoDB.
I have made a simple pager for the posts.
In the posts controller I have:
exports.getPosts = async (req, res, next) => {
const posts = await Post.find({}, (err, posts) => {
const perPage = 10;
const currPage = req.query.page ? parseInt(req.query.page) : 1;
const postsCount = posts.length;
const pageCount = Math.ceil(postsCount / perPage);
const pageDecrement = currPage > 1 ? 1 : 0;
const pageIncrement = currPage < pageCount ? 1 : 0;
if (err) {
console.log("Error: ", err);
} else {
res.render("default/index", {
moment: moment,
layout: "default/layout",
website_name: "MEAN Blog",
page_heading: "XPress News",
page_subheading: "A MEAN Stack Blogging Application",
currPage: currPage,
pageDecrement: pageDecrement,
pageIncrement: pageIncrement,
posts: posts,
});
}
})
.sort({ created_at: -1 })
.populate("category")
.limit(perPage)
.skip((currPage - 1) * perPage);
};
The pager in the view:
<% if (posts) {%>
<div class="clearfix d-flex justify-content-center">
<div class="px-1">
<a class="btn btn-primary <%= pageDecrement == 0 ? 'disabled' : '' %>" href="/?page=<%= currPage - pageDecrement %>">← Newer Posts</a>
</div>
<div class="px-1">
<a class="btn btn-primary <%= pageIncrement == 0 ? 'disabled' : '' %>" href="/?page=<%= currPage + pageIncrement %>">Older Posts →</a>
</div>
</div>
<% } %>
The problem
The line .limit(perPage)
from the controller gives the error perPage is not defined
in the console (Git bash).
The solution that does not work
Clearly, I can move these 2 lines above const posts
const perPage = 5;
const currPage = req.query.page ? parseInt(req.query.page) : 1;
but I can not do the same with const postsCount = posts.length;
(which I also need in the view).
The objective
I am trying to make the snippet of code regarding the pagination reusable (like a plugin, if possible), since I need to paginate for the posts filtered by category, and also the list of post in the admin section o the application.
What am I doing wrong?
回答1:
why are you using callback and await together.seems like you need to look in to async / await and promises.What you can do is as below:
exports.getPosts = async (req, res, next) => {
const currPage = req.query.page ? parseInt(req.query.page) : 1;
const perPage = 10;
try {
const posts = await Post.find({})
.sort({ created_at: -1 })
.populate("category")
.limit(perPage)
.skip((currPage - 1) * perPage).exec();
const postsCount = posts.length;
const pageCount = Math.ceil(postsCount / perPage);
const pageDecrement = currPage > 1 ? 1 : 0;
const pageIncrement = currPage < pageCount ? 1 : 0;
res.render("default/index", {
moment: moment,
layout: "default/layout",
website_name: "MEAN Blog",
page_heading: "XPress News",
page_subheading: "A MEAN Stack Blogging Application",
currPage: currPage,
pageDecrement: pageDecrement,
pageIncrement: pageIncrement,
posts: posts,
});
} catch (err) {
console.log("Error: ", err);
// add proper error handling here
res.render('default/error', {
err
});
}
};
回答2:
As a comment correctly points out, this seems to be an issue of scoping.
exports.getPosts = async (req, res, next) => {
// getPosts local scope
const posts = await Post.find({}, (err, posts) => {
// ... local scope
const perPage = 10;
const currPage = req.query.page ? parseInt(req.query.page) : 1;
const postsCount = posts.length;
const pageCount = Math.ceil(postsCount / perPage);
const pageDecrement = currPage > 1 ? 1 : 0;
const pageIncrement = currPage < pageCount ? 1 : 0;
if (err) {
console.log("Error: ", err);
} else {
res.render("default/index", {
moment: moment,
layout: "default/layout",
website_name: "MEAN Blog",
page_heading: "XPress News",
page_subheading: "A MEAN Stack Blogging Application",
currPage: currPage,
pageDecrement: pageDecrement,
pageIncrement: pageIncrement,
posts: posts,
});
}
// ... local scope ended
})
.sort({ created_at: -1 })
.populate("category")
// perPage == undefined
.limit(perPage)
.skip(currPage - 1)) * perPage;
};
Move const perPage
to above the const posts
and it'll be within the correct scope/context.
exports.getPosts = async (req, res, next) => {
const perPage = 10;
// getPosts local scope
const posts = await Post.find({}, (err, posts) => {
// ... rest of func
});
// .. rest of func
};
回答3:
Maybe if you check this component, you can solve your problem by seeing how it works
Mongoose Paginate
$ npm install mongoose-paginate
/**
* querying for `all` {} items in `MyModel`
* paginating by second page, 10 items per page (10 results, page 2)
**/
MyModel.paginate({}, 2, 10, function(error, pageCount, paginatedResults) {
if (error) {
console.error(error);
} else {
console.log('Pages:', pageCount);
console.log(paginatedResults);
}
}
回答4:
As explained by other comments. This could just be a problem with scope.
exports.getPosts = async (req, res, next) => {
const perPage = 10; // enable you to use perPage inside getPosts()
let postsCount = 0; // let, to enable you to use/reassigned postsCount inside getPosts()
const posts = await Post.find({}, (err, posts) => {
// ...
postsCount = posts.length; // updates the variable with the correct count
// ...
if (err) {
console.log("Error: ", err);
} else {
res.render("default/index", {
//...
posts: posts,
postsCount: posts.length, // for explicit postsCount in the view
});
}
});
// ..
for you problem with postsCount in the view, since you already have posts
in you view
<% if (posts) {%>
...
<% } %>
I think you can just use posts.length
or postsCounts
in the view like how you use the others(e.g pageIncrement, currPage, pageIncrement);
回答5:
As I found out recently postsCount = posts.length
counts the posts after they are limited by .skip((currPage - 1) * perPage)
, so the pageIncrement
variable "equation" turns to:
let pageIncrement = postsCount >= perPage ? 1 : 0;
So I get, in the controller:
exports.getPosts = async (req, res, next) => {
const perPage = 5;
const currPage = req.query.page ? parseInt(req.query.page) : 1;
let postsCount = 0;
const posts = await Post.find({}, (err, posts) => {
postsCount = posts.length;
let pageDecrement = currPage > 1 ? 1 : 0;
let pageIncrement = postsCount >= perPage ? 1 : 0;
if (err) {
console.log('Error: ', err);
} else {
res.render('default/index', {
moment: moment,
layout: 'default/layout',
website_name: 'MEAN Blog',
page_heading: 'XPress News',
page_subheading: 'A MEAN Stack Blogging Application',
currPage: currPage,
posts: posts,
pageDecrement: pageDecrement,
pageIncrement: pageIncrement
});
}
})
.sort({
created_at: -1
})
.populate('category')
.limit(perPage)
.skip((currPage - 1) * perPage);
};
And in the view:
<a class="btn btn-primary <%= pageDecrement == 0 ? 'disabled' : '' %>" href="/?page=<%= currPage - pageDecrement %>">← Newer Posts</a>
and
<a class="btn btn-primary <%= pageIncrement == 0 ? 'disabled' : '' %>" href="/?page=<%= currPage + pageIncrement %>">Older Posts →</a>
That works fine unless there are is a number of posts equal to perPage x N
, where N is an integer, in which case the "Older Posts" button becomes disabled one page too late.
来源:https://stackoverflow.com/questions/61718540/how-can-i-pass-express-js-variables-to-mongodb-functions