meteor .publish on server side: working with a client variable - meteor

I am building a chat and based on the chatroom selected by the currentUser, I want to publish messages with this function:
Meteor.publish('messages',function(){
return Messages.find(
{chatId: 'QMMjBgCvLcnLvJPvx'},
sort:{timestamp: -1}
});
});
Now the chatId is still hardcoded, but it needs to be dynamic. The chatId is passed in the URL(e.g..../chat/QMMjBgCvLcnLvJPvx). In the client based code I have used to read the chatId:
var chatId = Router.current().params._id;
Iron Router
But this doesn't work server side. Is there a way to send the chatId from the URL to the server so I use Meteor.publish as mentioned above. Any help appreciated :)

Pass in the variable when you subscribe I.e.
Meteor.subscribe("messages", {chatId: Session.get("current-room")})
In the publication:
Meteor.publish('messages',function(chatId){
return Messages.find(
{chatId: chatId},
sort:{timestamp: -1}
});
});

In your route, you can subscribe to a publication and pass a param inside waitOn which will cause the app to show your loading template until the subscription is ready and the chatId will be reactive.
Configure loading template:
Router.configure({
layoutTemplate:'templateName',
loadingTemplate: 'anotherTemplateName'
});
Your route:
Router.route('/chat/:_id',{
waitOn: function(){
return Meteor.subscribe('messages', this.params._id);
},
action: function(){
//render your template with data
this.render('templateName', {
data: function () {
//will return object to the template which you can use in both HTML and JS. Also necessary for the link.
return Somethings.findOne({_id: this.params._id})
}
})
}
});
Publication:
Meteor.publish("messages", function (chatId) {
//the chatId comes from our subscribe in our route
return Messages.find({chatId: chatId});
});

Thanks for your answers and the hints. After some more modifications I arrived at this, which solved the issue:
var chatId = Router.current().params._id
this.wait(Meteor.subscribe('messages', chatId));

Related

Meteor: Publishing all user not working without autopublish package

I would to show a list of all users, in my template.
I have:
//publications.js
Meteor.publish('users', function() {
return Meteor.users.find({}, { fields: {username: 1, profile: 1} });
});
//router.js
Router.route('/users/add/:_id?', {name: 'users.add', controller: 'UserAddController'});
UserAddController = RouteController.extend({
subscriptions: function(){
return [ Meteor.subscribe('hospitals'),
Meteor.subscribe('roles'),
Meteor.subscribe('users') ];
},
action: function() {
this.render('addUser', {
data: function(){
return { hospital_id : this.params._id }
}
});
}
});
//client
Template.listUsers.helpers({
users: function() {
return Meteor.users.find({});
}
});
But the list keep showing only the current logged-in user. I have created a list of users using Account.createUser() function What am I doing wrong?
Thanks.
You have to subscribe to a publication using this.subscribe() in subscriptions hook:
// a place to put your subscriptions
subscriptions: function() {
this.subscribe('items');
// add the subscription to the waitlist
this.subscribe('item', this.params._id).wait();
}
Or use waitOn:
// Subscriptions or other things we want to "wait" on. This also
// automatically uses the loading hook. That's the only difference between
// this option and the subscriptions option above.
waitOn: function () {
return Meteor.subscribe('post', this.params._id);
}
By default, Meteor publishes the current user. I see that you have a addUser template and a listUsers template. The problem is that while addUser is subscribed to the users publication, listUsers is not (this would depend on what else you have in your router of course). To fix this, change the call to this.render to render the listUsers template. Then, your users helper should work, and you can render the information however you like.
I tested this with my own app (the Microscope project from DiscoverMeteor) and it worked for me. Hope it works for you too. Comment here if not, and be sure to accept this answer if it worked. =)

How do I unsubscribe from the subscription set by Iron Router's waitOn?

I have a list of items fetched from a collection and I want to make it show different stuff depending what button is clicked. I figured I'd do this via sessions that update the publication.
Here's my publication:
Meteor.publish('stuff', function(filter) {
var nameVar = filter || "default"
return myStuff.find({name: nameVar})
})
Which I subscribe to in my router:
Router.route('/', {
name: 'home',
layoutTemplate: 'homeLayout',
waitOn: function() {
return Meteor.subscribe('stuff', Session.get('filter'));
}
});
Then make the buttons do their thing (they each have an id that matches what I want to filter by):
Template.buttonFilter.events({
'click button': function(event, template) {
var buttonId = event.currentTarget.id
Meteor.subscribe('stuff', Session.set('filter', buttonId))
}
})
However, when I click a button it won't unsubscribe from what I first subscribed to via the router, only from what was set on my last button click. I don't really understand why or how to fix it.
Edit: I don't believe this to be a duplicate since the answers to the other questions talk about changing routes, which I'm not doing.
It sounds like what you want (correct me if I'm wrong) is not so much to unsubscribe from the prior search, but to reactively subscribe to the current search and drop all records that are not encompassed by it. If so, you don't need to manually manage unsubscribing - Meteor will do that for you; you just need to make your subscription reactive.
Iron Router's waitOn will not rerun each time the subscription changes. To do that there are a few options. The quick and dirty option is to move the subscription from waitOn to onBeforeAction which will be rerun each time:
Router.route('/', {
name: 'home',
layoutTemplate: 'homeLayout',
onBeforeAction: function() {
Meteor.subscribe('stuff', Session.get('filter'));
this.next(); //make sure to include
}
});
Alternatively you can do it outside the router:
Tracker.autorun(function(){
var filter = Session.get('filter');
Meteor.subscribe('stuff', filter);
});
In either case you don't need to change the subscription from template.events - just change the session value.
Template.buttonFilter.events({
'click button': function(event, template) {
var buttonId = event.currentTarget.id;
Session.set('filter', buttonId);
}
});

Meteor.publish -> All data still available

In my server folder I have a file where i'm doing the following
Meteor.publish("all_jobs", function(jobs) {
return Jobs.find();
});
Meteor.publish("user_jobs", function(user_id) {
return Jobs.find({userid: user_id}, {sort: {date: -1}});
});
On the user his blogpost page I do the following:
Session.set("userid", Meteor.userId());
Meteor.subscribe("user_jobs", Session.get("userid"));
Template.userJobs.helpers({
jobs: function(){
return Jobs.find();
}
});
On my homepage I would need all the blogpost. So i'm trying to access Meteor.subscribe("all_jobs");
The problem i'm having right now is that all the posts are showing up on my user profile instead of only the posts published by the user.
Any suggestions?
Thanks
When you make multiple subscriptions for the same collection, the results will be merged on the client. After subscribing to all_jobs, the client will now have all of the jobs in its local database until the subscription is stopped. When you go to find some of the jobs in the userJobs template, you will need to indicate which ones you actually are interested in. Modify your helper as follows:
Template.userJobs.helpers({
jobs: function() {
return Jobs.find(userid: Meteor.userId());
}
});
Found the problem. The problem was I was subscribed to all the publications because I just subscribed somewhere random in my code.
I fixed this by adding a waitOn in my route:
waitOn: function() {
return [
Meteor.subscribe("userJobs"),
];
},

Meteor Iron Router Run function when collection changes

Im new to Meteor and Im trying to figure out how to run a function after a collection change.
I have a route(iron router) that subscribes to a collection with waitOn. Which just waits for the subscrition to be ready before rendering which is what I want.
waitOn: function () {
return Meteor.subscribe('collection', this.params._id);
},
Any changes to the collection will be updated on all the clients and rendered automatically.
How would I run a function once the collection has changed?
You can use the onData hook, provided that you're returning that data using the data helper. E.g this is what a route may look like
this.route('routename',
path : '/abc',
waitOn: function () {
return Meteor.subscribe('collection', this.params._id);
},
data: function() {
return Collection.findOne({_id: this.params.id});
}
onData: function() {
//Do something when the data found by the above changes
}
});

Meteor: Subscription doesn't work

I'm trying to get a document from the server and display it on the client but the subscription always return a collection with no document.
// server/publications.js
Meteor.publish('myPages', function() {
return Pages.findOne({userId: this.userId});
});
// collection/pages.js
MyPages = new Meteor.Collection('myPages');
// client/main.js
Meteor.subscribe('myPages');
// client/view.js
Template.myView.helpers({
myPages: function(e, t) {
console.debug(MyPages.find({}));
return MyPages.find({});
}
});
You cannot move a document between collections via a subscription. If you subscribe to get a document that's in Pages collection, defined as new Meteor.Collection("pages"), then no matter how your pubsub channels look like, on the client the document will be found in the collection defined as new Meteor.Collection("pages"). So remove all traces of MyPages and use Pages on the client as well. You'll find the document there.
I don't think you can use findOne to publish collections: it doesn't return a cursor but an actual object.
Does this not work?
Meteor.publish('myPages', function() {
return Pages.find({userId: this.userId});
});
or, if necessary:
Meteor.publish('myPages', function() {
return Pages.find({userId: this.userId}, {limit: 1});
});

Resources