Meteor Streams : client doesn't receive streams - meteor

i'm working on a simple app based on meteor and MeteorStreams.
The aim is simple :
one user will click on a button to create a room
other users will join the room
those users can emit streams with simple message
the creator will listen to that message and then display them
In fact : message from other users are sent (log in server script), but the creator doesn't receive them.
If i reload the page of the creator, then it will get messages sent from other user.
I don't really understand why it doesn't work the first time.
I use meteor-router for my routing system.
Code can be seen here
https://github.com/Rebolon/MeetingTimeCost/tree/feature/pokerVoteProtection
for the client side code is availabel in client/views/poker/* and client/helpers
for the server stream's code is in server/pokerStreams.js
Application can be tested here : http://meetingtimecost.meteor.com
The creator must be logged.
If you have any idea, any help is welcome.
Thanks

Ok, Ok,
after doing some debugging, i now understand what is wrong in my code :
it's easy in fact. The problem comes from the fact that i forgot to bind the Stream.on event to Deps.autorun.
The result is that this part of code was not managed by reactivity so it was never re-run automatically when the Session changed.
The solution is so easy with Meteor : just wrap this part of code inside the Deps.autorun
Meteor.startup(function () {
Deps.autorun(function funcReloadStreamListeningOnNewRoom () {
PokerStream.on(Session.get('currentRoom') + ':currentRoom:vote', function (vote) {
var voteFound = 0;
// update is now allowed
if (Session.get('pokerVoteStatus') === 'voting') {
voteFound = Vote.find({subscriptionId: this.subscriptionId});
if (!voteFound.count()) {
Vote.insert({value: vote, userId: this.userId, subscriptionId: this.subscriptionId});
} else {
Vote.update({_id: voteFound._id}, {$set: {value: vote}});
}
}
});
});
});
So it was not a Meteor Streams problem, but only my fault.
Hope it will help people to understand that outside Template and Collection, you need to wrap your code inside Deps if you want reactivity.

Related

How do I reliably pull data from Meteor server collections to client collections when using an existing mongodb as MONGO_URL?

I know that there are several methods to share collections on both the client and server -- namely either in top level lib folder or publish/subscribe model -- but when I try either of these things when using mongodb running at localhost:27017 as my MONGO_URL, I am not reliably getting data on the client. Occasionally console.log(myCollection.findOne({})) will return expected data in the browser but most of the time it returns undefined.
//Client side code
Template.controls.onCreated(function controlsOnCreated() {
Meteor.subscribe("myEvents");
Events = new Mongo.Collection("events");
});
//Server side code
Meteor.startup(() => {
Events = new Mongo.Collection("events");
}
Meteor.publish('myEvents', function() {
console.log(Events.find());
return Events.find();
});
UPDATED CODE -- returns Events on server but not client:
//Client
Template.controls.onCreated(function controlsOnCreated() {
this.subscribe("myEvents");
});
//Server
if (Meteor.isServer) {
Meteor.publish("myEvents", function() {
return Events.find();
});
}
// /collections/events.js
Events = new Mongo.Collection("events");
UPDATE 2:
I am attempting to verify the publication in the browser after the page has rendered, calling Events.findOne({}) in the Chrome dev tools console.
on your client:
Template.controls.onCreated(function controlsOnCreated() {
Meteor.subscribe("myEvents");
Events = new Mongo.Collection("events");
});
that is an odd place to define the Events variable. typically, you would put that line of code in a JS file common to both platform. e.g.
collections/events.js:
Events = new Mongo.Collection("events");
when that line runs on the server, it defines the mongo collection and creates a server-side reference to it. when it runs on the client, it creates a collection by that name in mini-mongo and creates a client-side reference to it.
you can write your onCreated like this (note "this" instead of "Meteor"):
Template.controls.onCreated(function() {
this.subscribe("myEvents");
});
you don't say where on the client you ran your console.log with the find(). if you did it in the onCreated(), that's too early. you're seeing the effects of a race condition. typically, you might use it in a helper:
Template.controls.helpers({
events() {
return Events.find({});
}
});
and display the data in the view:
{{#each event in events}}
{{event.name}}
{{/each}}
that helper will run reactively once the data from the publish shows up.

session email become undefined when i reload page in meteor JS

i store email using session .set('email','email name') but when i reload page that time this session email is become undefined. i use Session.get('email') to get user email.
Router.route('profile', {
path: '/profile',
data: function() {
$("body").removeClass('home');
this.render('profile');
setTimeout(function(){
$('#username').html(Session.get('first_name'));
$('#profile_username').html(Session.get('first_name'));
$('#setting_name').val(Session.get('first_name'));
$('#setting_username').val(Session.get('first_name'));
$('#setting_email').val(Session.get('email'));
$('#user_id').val(Session.get('id'));
$('.setting_day').val(Session.get('day'));
$('.setting_month').val(Session.get('month'));
$('.setting_year').val(Session.get('year'));
if(Session.get('image')!= ''){
$('.user_profile_image').attr("src",Session.get('image'));
}
if(Session.get('gender') == 0){
$('#user_gender').html('Male');
}else{
$('#user_gender').html('Female');
}
$('#day').html(Session.get('day'));
$('#month').html(Session.get('month'));
$('#year').html(Session.get('year'));
},100);
},
onBeforeAction: function () {
alert(Session.get('email'));
if(Session.get('email')){
this.next();
}else {
this.redirect('/');
}
}
});
install persistent package Session. Your session variables will persist across routes also. You need to configure it via Meteor settings. so don't forget include the settings when you run project.
u2622:persistent-session
When you reload the page page in meteor all the client side reactive things reinitialize So if you want to keep the email when page refresh then you have to send it on the server and then you can fetch this when according to your need. You can save it into a collection and then fetch from a meteor call or publish-subscribe according to your need.
When you refresh the page you are no longer in the same session so what you describe is the expected and correct default behavior. There is a package (I don't know it's name right now, but should be easy to find on atmospherejs) which gives you Session.setPersistent(...). I think this is what you are looking for.

node.js, css validation, w3c banned me?

I apologize in advance for what I write through a translator, I am very bad at English.
I was faced with the following problem: I need to perform validation css files. To this end, I decided to use the NPM package w3c-css, first it worked, but then start giving "connected etimedout", in the course of research, I noticed that through the browser and the validator stops working.
Sniffer log at start of my script: link (<10 rep :( )
My code:
gulp.task('css', function() {
gulp.src('dev/sass/*.scss')
.pipe(through2.obj(function(file, enc, cb){
w3c_css.validate({text: file.contents.toString('utf8')}, function(err, data) {
if(err) {
// an error happened
console.error(err);
} else {
// validation errors
console.log('validation errors', data.errors);
// validation warnings
console.log('validation warnings', data.warnings);
}
});
cb(null, file);
}))
.pipe(gulp.dest('build/'));
});
What is the reason? It must be some mistake, or I block due to too frequent requests and it does not change? Maybe there is some other way to check the css files?
Thx!
From the "About" page of the CSS validation service of the W3C:
Can I build an application upon this validator? Is there an API?
Yes, and yes. The CSS Validator has a (RESTful) SOAP interface which should make it reasonably easy to build applications (Web or otherwise) upon it. Good manners and respectful usage of shared resources are of course customary: make sure your applications sleep() between calls to the validator, or install and run your own instance of the validator.
So yes, it seems you have been banned.
I don't know how to make a gulp task to be called from time to time. You may mount a local version of the CSS Validator webservice and editing the w3c-css package to point to your own server.
Make sure that your script will sleep for at least 1 second between requests.
From the manual:
Note: If you wish to call the validator programmatically for a batch
of documents, please make sure that your script will sleep for at
least 1 second between requests. The CSS Validation service is a free,
public service for all, your respect is appreciated. thanks.
To validate multiple links, use async + setTimeout or any related way to pause between the requests:
'use strict';
var async = require('async');
var validator = require('w3c-css');
var hrefs = [
'http://google.com',
'https://developer.mozilla.org',
'http://www.microsoft.com/'];
async.eachSeries(hrefs, function(href, next) {
validator.validate(href, function(err, data) {
// { process err, data.errors & data.warnings }
// sleep for 1.5 seconds between the requests
setTimeout(function() { next(err); }, 1500);
});
}, function(err) {
if(err) {
console.log('Failed to process an url', err);
} else {
console.log('All urls have been processed successfully');
}
});
EDIT:
To mitigate this issue:
Added some comments and an example.
Placed setTimeout right into the gulp-w3c-css plugin.

Publishing Meteor Users to Admin

I'm trying to publish all emails and "roles" to "admin" users (using the meteor-roles meteorite package), and the server knows what it's trying to publish, but for some reason the client is not picking up the data. Here's the piece of code involved:
Server Code:
Meteor.publish("directory", function() {
if(Roles.userIsInRole(this.userId, 'admin')) {
//next line shows that it outputs that there are 2 documents in this
console.log(Meteor.users.find({}, {fields:{emails:1, roles:1}}).count());
return Meteor.users.find({}, {fields:{emails:1, roles:1}});
} else {
return {};
}
}
Client Code:
Meteor.subscribe("directory");
Directory = new Meteor.Collection("directory");
//and then to simulate my use for this collection
console.log(Directory.find().count());
//which outputs 0
Why isn't the client getting the documents? (and I am definitely logging in with an account with role "admin")
Thanks!
EDIT and SOLUTION!
Okay, so I figured out what I was doing wrong. I just need to publish "directory" on the server, and subscribe on the client. Then, all user data goes into the Meteor.users collection, and I shouldn't define my own "Directory=new Meteor.Collection('directory')". I can then access the data via Meteor.users. Cheers!
Server: use same code as above
Client:
Meteor.subscribe("directory");
console.log(Meteor.users.find().count()); //outputs 2, yay!
Your collection should probably be defined on the beginning so that client knows where to write!
Also, your Meteor.subscribe("directory"); runs once when the app is loaded. You should make it reactive.
Directory = new Meteor.Collection("directory");
Deps.autorun(function(){
Meteor.subscribe("directory");
});

Meteor - Using collection on client startup

Why this code shows "0"? Shouldn't it return "1"?
Messages = new Meteor.Collection("messages");
if (Meteor.is_client) {
Meteor.startup(function () {
alert(Messages.find().count());
});
}
if (Meteor.is_server) {
Meteor.startup(function () {
Messages.insert({text: "server says hello"});
});
}
If I do the "Messages.find().count()" later, it returns 1.
By default, when a Meteor client starts up, it connects to the server and subscribes to documents in any Meteor.Collection you defined. That takes some time to complete, since there's always some amount of delay in establishing the server connection and receiving documents.
Meteor.startup() on the client is a lot like $() in jQuery -- it runs its argument once the client DOM is ready. It does not wait for your client's collections to receive all their documents from the server. So the way you wrote the code, the call to find() will always run too early and return 0.
If you want to wait to run code until after a collection is first downloaded from the server, you need to use Meteor.subscribe() to explicitly subscribe to a collection. subscribe() takes a callback that will run when the initial set of documents are on the client.
See:
meteor-publish
and meteor-subscribe
Just to follow up with a code example of how to know when a collection is ready to use on the client.
As #debergalis described, you should use the Meteor.subscribe approach - it accepts a couple of callbacks, notably onReady
For example:
if(Meteor.isClient){
Meteor.subscribe("myCollection", {
onReady: function(){
// do stuff with my collection
}
});
}

Resources