I am having issues with pagination I\'ve implemented. Pagination works based on server-sided publish skip & limit filter.
Issue #1. If I perform a specific user
Use below code for pagination. It is very ideal code, easy to understand and implement.
SERVER PUBLISH:
Meteor.publish('Students', function (str, toSkip, tillLimit) {
var regex = new RegExp(str, 'i');
var data = Students.find( {
$or:[
{"_id": {'$regex' : regex}},
{"username": {'$regex' : regex}}
]
},
{sort: {'time': -1}, skip: toSkip, limit : tillLimit});
return data;
});
Meteor.publish('StudentsTotalCount', function (str) {
var regex = new RegExp(str, 'i');
Counts.publish(this, "StudentsTotalCount", Students.find({
$or:[
{"_id": {'$regex' : regex}},
{"username": {'$regex' : regex}}
]
});
);
});
str
is global search text from client side. Now, Since the user will click on next
and previous
button frequently. On the client side the Subscription must be reactive. For that you can you below code.
CLIENT SUBSCRIBE:
Inside some App_ShowStudents.js
file, you can create subscription as below;
Template.App_ShowStudents.onCreated(function(){
this.userId = new ReactiveVar("");
this.filterCriteria = new ReactiveVar("");
//PAGINATION
this.enablePrevious = new ReactiveVar(false);
this.enableNext = new ReactiveVar(true);
this.skip = new ReactiveVar(0);
this.diff = new ReactiveVar(0);
this.total = new ReactiveVar(0);
this.limit = new ReactiveVar(10);
this.autorun(() => {
Meteor.subscribe('Students', this.filterCriteria.get(), this.skip.get(), this.limit.get());
Meteor.subscribe('StudentsTotalCount', this.filterCriteria.get(), this.role.get());
});
});
HELPERS:
Template.App_ShowStudents.helpers({
students(){
return Students.findOne({}); // this will always be less or equal to 10.
},
skip(){
return Template.instance().skip.get();
},
diff(){
var instance = Template.instance();
var add = instance.skip.get() + instance.limit.get();
var total = instance.total.get();
var diff = (add >= total ? total : add);
instance.diff.set(diff);
return instance.diff.get();
},
total(){
Template.instance().total.set(Counts.get('StudentsTotalCount'));
return Template.instance().total.get();
}
});
total
actually must be reactive and should give only count as per your search criteria, so we had a seperate publish on server.
EVENTS:
Template.App_ShowStudents.events({
'click .previous': function (event, template) {
event.preventDefault();
if(template.diff.get() > template.limit.get()){
template.skip.set(template.skip.get() - template.limit.get());
}
},
'click .next': function (event, template) {
event.preventDefault();
if(template.diff.get() < template.total.get()){
template.skip.set(template.skip.get() + template.limit.get());
}
},
'input #searchData': function( event, template ) {
if ( $( event.target ).val()) { // has some value.
template.filterCriteria.set( $( event.target ).val() );
} else {
template.filterCriteria.set( "" );
}
console.log(template.filterCriteria.get());
},
});
App_ShowStudents.html
{{#if Template.subscriptionsReady}}
Showing {{skip}} - {{diff}} of {{total}}
{{#each students}}
...
{{/each}}
{{else}}
Please wait...
{{/if}}