A Meteor server causes a collection update which also updates the client copy of the collection.
Is there a way to invoke a client function whenever a record in client copy of the collection gets updated? Thanks
//server
Meteor.users.update({
_id: Meteor.userId()
}, {
$set: {
'profile.goAhead': true
});
//client
if (Meteor.user().profile.goAhead) {
myFunc();
}
You want .observeChanges()
let query = MyCollections.find();
query.observeChanges({
added(id,fields){
console.log("Document added with _id "+id);
},
changed(id,fields){
console.log("Document with _id "+id+" was changed");
},
// ... there are more possible callbacks
});
Meteor has optimistic update. The client copy is first updated. Then at a convenient time, the server collection is updated. If there are any issues with the server update, then the client copy is rolled back or updated with different value.
In the above code, the server update should be wrapped in Meteor.methods(). Calling a server method from the client has a callback method which can be used in this case.
Related
This Meteor code gives full records to the client for one of the collections but the client browser gives:
MyCol.findOne({});
undefined
I also have a server side code which inserts documents into the collection and mongo terminal verifies documents exist.
Any idea why? Thanks
//app.lib.js
MyCol = new Mongo.Collection('myCol');
//server
Meteor.publish('myCol', function() {
return MyCol.find({});
});
//client main.js
Meteor.subscribe('myCol');
Template.checks.helpers({
'values': function() {
return MyCol.find({}); // no documents found,
}
});
With autopublish package is removed, While this Meteor code is running, a different userId has been confirmed on 2 different browsers consoles Meteor.userId();
But when a string is typed in the inputText of one of them, and a collection.insert is done, the other shows the same string.
I thought that this.userId was good enough for the server to publish only the documents that belongs to each of the different clients simultaneously.
Why is this happening and how to fix it? Thanks
Server
Meteor.publish('displayCol', function () {
return DisplayCol.find({userId: this.userId});
});
DisplayCol.before.insert(function (userId, doc) {
doc.userId = userId;
});
Client
Template.index.helpers({
taskInputs: function () {
var ready = Meteor.subscribe('displayCol').ready();
var data = DisplayCol.find({});
return {items: data, ready: ready};
}
});
Do you have autopublish still installed? If so, both clients will get everything automatically. Remove it with 'meteor remove autopublish'
You can also add the {userId: Meteor.userId()} condition on the client side.
I have an app where each User has a Counter object associated with it. The User is subscribed to the corresponding Counter.
Each time a user submits the form, I want to save the current value of the User's Counter to the form. However, the client and server disagree on what Counter object to use.
Counters = new Mongo.Collection("counters");
Router.route('/register', { name: 'insertRegistration',
waitOn: function() {
return [ Meteor.subscribe('counters') ];
},
});
RegistrationSchema = new SimpleSchema({
somevalue: {
type: String,
autoValue: function() {
console.log(Counters.findOne()); // Different results on client and server
return "whatever";
}
}
});
if (Meteor.isServer) {
Meteor.publish('counters', function() {
return Counters.find({ user_id: this.userId });
});
}
Counters.findOne() on the client picks the Counter object associated with the current user.
Counters.findOne() on the server picks a Counter object out of the collection of all Counter objects.
I think this is because the Client asks for Counters and gets what it's subscribed to, while Server asks for Counters and gets the Collection.
Is there a way to consider the publish/subscribe rules on the server?
On the server, do
Counter.findOne({ user_id: this.userId })
to get the correct counter for the user.
Is there any way to publish once the subscribe request is made and then stop pushing the changes that are made to the collection until the client subscribes again?
I have this scenario:
Server:
Meteor.publish("posts", function () {
return Messages.find(); //Do not push changes to this collection!
});
Client:
Meteor.subscribe("posts");
If you just have to do a one-shot data send to the client, using a method may work:
//Server
Meteor.methods({
getSomePosts : function(limit)
{
check(limit, Number);
return Posts.find({}, {limit : limit}).fetch();
}
});
//Client
Meteor.call('getAllPosts', function(err, result) {
//Do stuff with the result
});
Note that this will be heavy on your database, you may want to use a variable and update it periodically rather than fetching the whole collection each time a client calls the method.
More about limits in the doc!
I'm trying to see how can I invoke a js function after the client gets a result from a Meteor method call. The only thing I was able to get is to invoke the function myFunc only on the client that made the actual method call.
Any thoughts how i can invoke the function on all the currently subscribed clients?
here is the code:
function myFunc(error, result) {
alert(result);
}
if (Meteor.is_client) {
Template.container.events = {
'click input' : function () {
Meteor.call('someMethod',myFunc);
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
};
}
if (Meteor.is_server) {
Meteor.startup(function () {
// code to run on server at startup
});
}
Meteor.methods({
someMethod: function() {
//console.log(!this.is_simulation);
return "something";
}
})
Thanks
Currently you can't broadcast a method call to all clients directly. At least as far as I can tell. But a work around would be to create a collection called Alerts and monitor it for changes. Then when you want to send a message to all your users you can change the document in Alerts:
Client:
Alerts = new Meteor.Collection("alerts")
Meteor.autosubscribe(function() {
Alerts.find().observe({
added: function(item){
alert(item.message);
}
});
});
Server:
Alerts = new Meteor.Collection("alerts")
Meteor.publish("alerts", function(){
Alerts.find();
});
Alerts.remove({}); // remove all
Alerts.insert({message: "Some message to show on every client."});
Another option is using Meteor Stream package which purpose is to avoid using a mongodb collection on the server side. It does supports client to clients, server to clients, client to server AND server to servers messaging, including a support for Meteor Cluster
If you want to stay with meteor only using collections, the following code allows you to either broadcast a message from the client to all the clients or a message from the server to all the subscribed clients. Just use this mechanism to then fire a function on the client side once the right message is received. The code is made in such a way that you will never have useless items remaining into the collection.
Messages = new Meteor.Collection("messages");
if (Meteor.isClient) {
Meteor.subscribe("messages");
var query = Messages.find({});
var handle = query.observe({
added: function(document)
{
console.log(document.message);
}
});
// Test the mechanism from the client side
Meteor.call("client talked");
}
if (Meteor.isServer) {
Meteor.startup(function() {
Messages.remove({});
});
Meteor.publish("messages", function()
{
// you might add an optional filter in order to broadcast only the messages you want to the client
return Messages.find();
});
function talk(message)
{
var id = Messages.insert({"message":message});
Messages.remove(id);
}
Meteor.methods(
{
talk: function(message)
{
// you might filter here if the clients can talk using this.userId
talk(message);
}
});
// test the mechanism from the server side
talk("server talked");
}
I like what Zeke said, but for people who uses Meteor 0.5.0+, use Deps.autorun instead of autosubscribe... details at:
https://groups.google.com/forum/#!topic/meteor-core/mTa81RLvhbY
and
http://www.meteor.com/blog/2013/02/14/meteor-055-devshop-code-and-community-contributions
I simple approach to call a JavaScript client-side function would be to add a script tag in your html template that is bound by your collection. Anytime a new item is inserted, this tag would be inserted into the client would run your function. I have a collection call uploads with some properties such as name. The following template triggers drawpoints() client-side function upon receipt of a new item in Uploads collection:
{{#each uploads}}
<tr>
<td>{{name}}</td>
<td>
<div class="alert alert-success">Download Here</div>
</td>
</tr>
<script>drawpoints();</script>
{{/each}}