Reputation: 21
Im using Nodejs, EJS, Mongoose and MongoDB and i have a table that is created from the documents in my DB and cant get paging buttons to work without clearing my search query.
The way my app works is
Click on the search link which opens a search filter page. My Search page
Then you select you filer and search. Results are then shown. With Search Query in URL Searched Results with Search Query
3.When you click on the next page it clears your query. Page buttons
Here is my paging buttons and below is my route My search filters are on another page.
<div class="container">
<nav aria-label="...">
<ul class="pagination float-right">
<li class="page-item disabled">
<span class="page-link">Previous</span>
</li>
<li class="page-item active">
<a class="page-link" name="1" href="/searched/1">1</a>
</li>
<li class="page-item">
<a class="page-link" name="2" href="/searched/2">2</a>
</li>
<li class="page-item">
<a class="page-link" name="3" href="/searched/3">3</a>
</li>
<li class="page-item">
<a class="page-link">Next</a>
</li>
</ul>
</nav>
</div>
app.get("/searched/:page/:limit", function (req, res) {
if (req.isAuthenticated()) {
// const { page, limit } = req.params;
// const options = {
// sort: { dateAdded: -1 },
// page: page,
// limit: limit,
// };
const query = req.query;
if (query.btu === "") {
delete query.btu;
}
if (query.sn1 === "") {
delete query.sn1;
}
if (query.sn2 === "") {
delete query.sn2;
}
if (query.userCreated === "") {
delete query.userCreated;
}
if (query.split === "") {
delete query.split;
}
if (query.supplier === "") {
delete query.supplier;
}
if (query.issued === "") {
delete query.issued;
}
// Aircon.paginate(query, options, function (err, foundAircons) {
// if (err) {
// console.log(err);
// } else {
// console.log(foundAircons);
// res.render("instock", {
// foundAircons: foundAircons.docs,
// });
// }
// });
Aircon.find(query)
.sort({
dateAdded: "desc",
})
.exec((err, foundAircons) => {
if (err) {
console.log(err);
} else {
res.render("instock", {
foundAircons: foundAircons,
});
}
});
} else {
res.redirect("/login");
}
});
Upvotes: 2
Views: 1916
Reputation: 21
managed to get it working as well with mongoose paginate v2 and found a function to rebuild the query string and pass back to the buttons
function objectToQueryString(obj) {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
}
app.get("/searched", function (req, res) {
if (req.isAuthenticated()) {
const { page } = req.query;
const options = {
sort: { dateAdded: -1 },
page: !page ? 1 : page,
limit: 20,
};
const query = req.query;
delete query.page;
if (query.btu === "") {
delete query.btu;
}
if (query.sn1 === "") {
delete query.sn1;
}
if (query.sn2 === "") {
delete query.sn2;
}
if (query.userCreated === "") {
delete query.userCreated;
}
if (query.split === "") {
delete query.split;
}
if (query.supplier === "") {
delete query.supplier;
}
if (query.issued === "") {
delete query.issued;
}
var queryString = objectToQueryString(query);
console.log(queryString);
Aircon.paginate(query, options, function (err, results) {
if (err) {
console.log(err);
} else {
res.render("instock", {
foundAircons: results.docs,
total: results.totalDocs,
hasPrev: results.hasPrevPage,
hasNext: results.hasNextPage,
pageCount: results.totalPages,
page: results.page,
url: queryString,
});
}
});
} else {
res.redirect("/login");
}
});
<div class="container">
<nav aria-label="...">
<ul class="pagination float-right">
<% let prev = "disabled"; if(hasPrev){ prev = "" }; %>
<li class="page-item <%= prev %>">
<a class="page-link" href="/searched/?<%= url %>&page=<%= page - 1 %>"
>Previous</a
>
</li>
<% for(let i = 1; i <= pageCount; i++){ %> <% let active = ""; %>
<%if(page === i) { active = "active"} %>
<li class="page-item <%= active %>">
<a class="page-link" name="1" href="/searched/?<%= url %>&page=<%= i %>"
><%= i %></a
>
</li>
<% }; %> <% let next = "disabled"; if(hasNext){ next = "" }; %>
<li class="page-item <%= next %>">
<a class="page-link" href="/searched/?<%= url %>&page=<%= page + 1 %>"
>Next</a
>
</li>
</ul>
</nav>
</div>
Upvotes: 0
Reputation: 2189
Actually, your structure looks unfamiliar to me. I'm not sure have you ever heard "pagination token" term. If you didn't you can check this magnificent guide.
I wrote searching endpoint with parameters like searchTerm
, limit
and pageToken
to paginate. pageToken
is important. If you want to go page: 2 for example. page token should be first record after the last record of the first page results. I used _id
parameter in this example
Note: Creating index is mandatory for filter the records with searchTerm
. Index creation is like this:
await db.collection(feedSettings._collection).createIndex({ "$**": "text" }, { name: "TextIndex" });
Code:
exports.pagination = async (req, res, next) => {
const db = await database.mongo;
const feedSettings = req.feedSettings;
// Query parameters
const limit = parseInt(req.query.limit) || 100;
let searchTerm = req.query.searchTerm;
let pageToken = req.query.pageToken;
const query = { _feedName: feedSettings.name };
// Start from last item
let paginatedQuery = {
_feedName: feedSettings.name,
_id: { $gt: ObjectID(pageToken) },
_trashed: { $ne: true }
}
// If we don't have a pageToken start from first item
if (!pageToken) {
let firstFeed = await db.collection(feedSettings._collection).findOne(query, { projection: { _id: 1 } });
if (!firstFeed) {
return res.status(200).json({
success: 1,
data: []
});
}
paginatedQuery._id = { $gte: ObjectID(firstFeed._id) };
}
// If user doesn't want to search a term in items
if (typeof searchTerm === 'string') {
await db.collection(feedSettings._collection).createIndex({ "$**": "text" }, { name: "TextIndex" });
paginatedQuery.$text = { $search: searchTerm };
}
feedsData = await db.collection(feedSettings._collection)
.find(paginatedQuery)
.limit(limit)
.toArray();
return res.status(200).json({
success: 1,
data: feedsData
});
}
Upvotes: 1