I have a dropdownlist as filters and then there's the total posts with a limit of displaying only 4 at a time unless a load more button is clicked to show another 4 records. problem is the dropdownlist is also loading values only from that first 4 records.
Here is my publication
Meteor.publish('allJobs', function(limit){
if(!limit){
return Jobs.find();
}
return Jobs.find({}, {limit: limit});
});
my main subscription in the controller
waitOn: function() {
return Meteor.subscribe("allJobs",4,this.findOptions());
},
helpers for the template
Template.jobsList.helpers({
'allJobs': function(){
var filter ={};
var category = Template.instance().selectedCategory.get();
var city = Template.instance().selectedCity.get();
var jtype = Template.instance().selectedJobType.get();
if(jtype)
filter.jtype = jtype;
if(city)
filter.city = city;
if(category)
filter.ccategory = category;
return Jobs.find(filter);
},
'moreResults': function(){
return !(Jobs.find().count() < Session.get("jobsLimit"));
}
});
Template.jobsList.onRendered(function(){
Session.setDefault("jobsLimit", 4);
this.autorun(function(){
Meteor.subscribe("allJobs", Session.get("jobsLimit"));
});
});
i tried to make another subscription for this but it didn't work out. Please help with a best solution.
Template
<template name="jobsList">
<div class="col s12 filter-holder">
<div class="col m4 s4 filter-box">
{{> categoryFilter}}
</div>
<div class="col m4 s4 filter-box">
{{> cityFilter}}
</div>
</div>
<div class="col s12">
<ul class="collection" id="listings">
{{#each allJobs}}
<li>
{{> jobItem}}
</li>
{{/each}}
</ul>
{{#if moreResults}}
<button class="load-more" id="showMoreResults" type="submit">Load More
<i class="mdi-content-send right"></i>
</button>
{{/if}}
</div>
</template>
Please help i am stuck in this situation
Updated js file
var limit = new ReactiveVar;
var filterAndLimitResults = function (cursor, limit) {
if (!cursor) {
return [];
}
var chosenCategory = limit.get("chosenCategory");
var raw = cursor.fetch();
// filter category
var filtered = [];
if (!chosenCategory || chosenCategory == "") {
filtered = raw;
} else {
filtered = _.filter(raw, function (item) {
return item.category === chosenCategory;
});
}
if (limit) {
filtered = _.first(filtered, limit);
}
return filtered;
};
//template created function
Template.jobsList.onCreated(function(){
limit.set(4);
limit.set("chosenCategory");
});
// Template helper function
Template.jobsList.helpers({
"displayedJobs": function() {
return filterAndLimitResults(Jobs.find(), (limit.get()));
},
'moreResults': function(){
return !(Jobs.find().count() < limit.get());
}
});
Dropdown click filtering
Declaring in rendered function
Template.jobsList.onRendered(function(){
limit.set(4);
chosenCategory.set();
});
And the click event is as follows
"click .categoryselection": function(e, t){
e.preventDefault();
chosenCategory.set(chosenCategory.get());
First, just to be sure I understand your situation, let me rephrase it:
You have a collection of documents that you want to sort using categories (which are stored for each document in a dedicated field).
On one hand, you want to build a dropdown using all the possible categories in your collection documents in order to allow the user to select a category and filter the results.
On the other hand, you want to display only 4 items at a time. These 4 displayed items (and those who could be loaded after them) are the 4 first items matching the filtered category.
Your choice of displaying items 4 by 4 is only to avoid to put too much content in user interface
What I advise you is:
You don't need to limit the items you load using your publication. First, it will slow down your user interface (you have to request to the server each time), second you wont be able to achieve the filtering as you may have noticed.
Step by step:
- replace your publication with a simple
return Jobs.find();
This is not the place where you need to do your filtering or enforce limit to the number of displayed items. It means that now, if you add a console.table(Job.find().fetch());
you will get all the available jobs for display. That will make the dropdown display all the categories you need, using the _.uniq
I advised you to use in your precedent question
You create a Session variable (or a reactive variable using ReactiveVar
) to store your current limit. you initate it in your template rendered
function, or even in the template created
function: pageSession.set("limit", 4);
and you modify it as you need in your "load more" button click event.
You will create a function in your client code in order to enforce your rules (limit to displayed items number and categry filtering). Let's call it filterAndLimitResults
. The helper that you use to return the displayed jobs will become something like this:
"displayedJobs": function() {
return filterAndLimitResults(Job.find());
}
You don't need a "moreResults" helper. Get rid of that. You just create an event on click on the more results button where you update your ReactiveVar
Template.jobsList.events({
"click #showMoreResults": function(e, t) {
e.preventDefault();
limit.set(limit.get()+4);
},
You create a Session variable (or a reactive variable using ReactiveVar
) in order to store your currently selected category. you initate it in your template rendered
function, or even in the template created
function: pageSession.set("chosenCategory", "");
and you modify it as you need in your dropdown items click event.
You need now to write your filterAndLimitResults
. Here is an untested example:
var limit = new ReactiveVar;
var chosenCategory= new ReactiveVar;
var filterAndLimitResults = function (cursor) {
if (!cursor) {
return [];
}
var raw = cursor.fetch();
var currentChosenCategory = chosenCategory.get();
// filter category
var filtered = [];
if (!currentChosenCategory || currentChosenCategory == "") {
filtered = raw;
} else {
filtered = _.filter(raw, function (item) {
return item.category === currentChosenCategory ;
});
}
var currentLimit =limit.get();
// enforce your limit
if (currentLimit ) {
filtered = _.first(filtered, currentLimit );
}
return filtered;
};
And you should be good to go :-) You get your results almost instantly and they are reactive.
ps: following the same logic, you should have no trouble to filter by cities too and/or any other field.
Short answer in reply to your comment. If you want to filter the collection you need to do it on the server AND the client. Otherwise as I said before your client database will only contain the first 4 natural order records - the filtering you are currently doing is only looking at those 4 records. You want to publish anything that matches the filter (up to the limit) so that this is available on the client. You filter again on the client to ensure you're getting the correct documents.
TL;DR:
Meteor.publish('allJobs', function(limit){
if(!limit){
return Jobs.find();
}
return Jobs.find({}, {limit: limit});
});
should be something like
Meteor.publish('allJobs', function(limit, filter){
if(!filter) {
filter = {};
}
if(!limit) {
return Jobs.find(filter);
}
return Jobs.find(filter, {limit: limit});
});
Also make sure that this.findOptions()
in the line;
Meteor.subscribe("allJobs",4,this.findOptions());
is actually returning the filter object otherwise you'll still have the same issue.