meteor collection - leaderboard app - collections

What am i doing wrong?
I'm building the leaderboard app from meteortips.com
Trying to build a collection in the database this is my code:
new Meteor.Collection('players');
PlayersList = new Meteor.Collection('players');
if(Meteor.isClient) {
console.log("Hello Client");
}
if(Meteor.isServer) {
console.log("Hello Server");
}
Trying out PlayersList on the js console gives me an error:
PlayersList
ReferenceError: PlayersList is not defined
message: "PlayersList is not defined"
stack: (...)
stack: function () { [native code] }
set stack: function () { [native code] }
proto: Error

You’re defining the collection twice. Change:
new Meteor.Collection('players');
PlayersList = new Meteor.Collection('players');
to just:
PlayersList = new Meteor.Collection('players');

you must to create the collection of follows way
PlayersList = new Meteor.Collection('players');
and you have to pay attention where you create this collection, because if you want have this collection in the two sides, client and server, you must create the collection in one archive outside of client and server folder. This collection you can use in all your application.

Related

Unable to add data into Firebase

Im getting the following two errors when trying to upload my JSON into Firebase:
Console error
Factory:
angular
.module("ngClassifieds")
.factory("classifiedsFactory", function($http, $firebaseArray){
(
var ref = new Firebase('https://xxxxx.firebaseio.com/');
return {
ref: $firebaseArray(ref)
}
});
Controller:
.controller("classifiedsCtrl", function($scope, $http, classifiedsFactory, $mdSidenav, $mdToast, $mdDialog)
I am using the following code to upload my JSON into firebase.
var firebase = classifiedsFactory.ref //we have a variable pointing to our classifiedsFactory reference
angular.forEach(data, function (item) {
firebase.$add(item);
});
Please let me know where I'm going wrong here.

Polymer using firebase query with context

in my custom Polymer element, i have a method that queries a firebase instance like so:
_updateUser: function(user) {
if(this._firebaseRef) {
this._firebaseRef.off()
}
if(user) {
var userLocation = ['xxxxx.firebaseio.com', 'users', this.user.uid].join('/');
this._firebaseRef = new Firebase(userLocation);
var query = this._firebaseRef.orderByChild("username")
query.on("value", function(messageSnapshot) {
messageSnapshot.forEach(function(messageData){
this.set('usernames', []);
console.log(this);
});
},null, this);
}
},
However, I keep getting the following error Uncaught TypeError: this.set is not a function. It seems that this is not set as the context as expected as per the api documentation
May I know how I can call this.set in my callback successfully? Thanks.
You need to pass the context into the forEach function as well.
messageSnapshot.forEach(function (messageData) {...}, this)
or
messageSnapshot.forEach(function (messageData) {...}.bind(this))

Publishing data from external API in Meteor

For publishing a list of items coming from an external API, I followed the this tutorial: so I've a publication on the server called "items" and a collection with the same name on the client; iron-router is the trait d'union between them. So far so good.
Now I'm stuck in implementing the "item detail" route (e.g. /item/:id). I wrote a server method like this:
Meteor.methods({
'getItem': function(id) {
check(id, Match.Integer);
var self = this;
var asyncCall = Meteor.wrapAsync(requestToThirdParty);
// requestToThirdParty is local function which calls HTTP.get
var response = asyncCall('GET', id);
return response.data;
}
});
I don't know if it's the best way to do, but I'm wondering how to call this method from the following route:
Router.route('/items/:id', {
name: 'itemDetail',
data: function() {
var item = Meteor.call('getItem', this.params.id); // this should be sync
console.log('item: '+item);
return item;
}
});
I'm sure that the method on server works fine (I debugged), but the console log in the client always shows "undefined".
What am I missing?
Are there any other approaches?

How to emit data only to one client in Meteor streams

I am building a realtime game with Meteor streams. I need to update only one client - send a room ID from server. Users are not logged in so Meteor.userId() is null and therefore I can't use this: http://arunoda.github.io/meteor-streams/communication-patterns.html#streaming_private_page
There is only one URL (homepage) where all things happen. So I don't use any URL parameters for room. Everything is on the server.
I have tried to use Meteor.uuid() instead of Meteor.userId() but uuid is changed after each emit (which is strange).
In socket.io I would do this:
//clients is an array of connected socket ids
var clientIndex = clients.indexOf(socket.id);
io.sockets.socket(clients[clientIndex]).emit('message', 'hi client');
Is there any way to do this in Meteor streams or Meteor itself?
Well, this can be easily done if you decided to use database, but I guess it is not the best option if you have a large number of clients.
So another way to achieve this - without database - is to make a good use of the Meteor's publish/subscribe mechanism. Basically the way it could work is the following:
1. client asks server for a communication token (use Meteor.methods)
2. client subscribes to some (abstract) data set using that token
3. server publishes the required data based on the received token
So you will need to define a method - say getToken - on the server that generates tokens for new users (since you don't want to use accounts). This could be something more or less like this:
var clients = {}
Meteor.methods({
getToken: function () {
var token;
do {
token = Random.id();
} while (clients[token]);
clients[token] = {
dependency: new Deps.Dependency(),
messages: [],
};
return token;
},
});
A new client will need to ask for token and subscribe to the data stream:
Meteor.startup(function () {
Meteor.call('getToken', function (error, myToken) {
// possibly use local storage to save the token for further use
if (!error) {
Meteor.subscribe('messages', myToken);
}
});
});
On the server you will need to define a custom publish method:
Meteor.publish('messages', function (token) {
var self = this;
if (!clients[token]) {
throw new Meteor.Error(403, 'Access deniend.');
}
send(token, 'hello my new client');
var handle = Deps.autorun(function () {
clients[token].dependency.depend();
while (clients[token].messages.length) {
self.added('messages', Random.id(), {
message: clients[token].messages.shift()
});
}
});
self.ready();
self.onStop(function () {
handle.stop();
});
});
and the send function could defined as follows:
var send = function (token, message) {
if (clients[token]) {
clients[token].messages.push(message);
clients[token].dependency.changed();
}
}
That's a method I would use. Please check if it works for you.
I think using Meteor.onConnection() like a login would enable you to do what you want pretty easily in a publish function.
Something like this:
Messages = new Meteor.Collection( 'messages' );
if ( Meteor.isServer ){
var Connections = new Meteor.Collection( 'connections' );
Meteor.onConnection( function( connection ){
var connectionMongoId = Connections.insert( connection );
//example Message
Message.insert( {connectionId: connection.id, msg: "Welcome"});
//remove users when they disconnect
connection.onClose = function(){
Connections.remove( connectionMongoId );
};
});
Meteor.publish( 'messages', function(){
var self = this;
var connectionId = self.connection.id;
return Messages.find( {connectionId: connectionId});
});
}
if ( Meteor.isClient ){
Meteor.subscribe('messages');
Template.myTemplate.messages = function(){
//show all user messages in template
return Messages.find();
};
}
I have used database backed collections here since they are the default but the database is not necessary. Making Messages a collection makes the reactive publishing easy whenever a new message is inserted.
One way that this is different from streams is that all the messages sent to all clients will end up being kept in server memory as it tries to keeps track of all data sent. If that is really undesirable then you could use a Meteor.method so send data instead and just use publish to notify a user a new message is available so call the method and get it.
Anyway this is how I would start.

Can I publish only Collections object in meteor?

On the introducing article of DDP, I read that anything can be published, but I've read somewhere ( for example in this Stackoverflow comment Publish arbitrary data and automatically update HTML ) that only Collections can be published.
So where is the truth? If we can publish other things than Collections, I would liek to see an example as I can't find one so far.
From the docs: http://docs.meteor.com/#meteor_publish
Publish functions can return a Collection.Cursor, in which case Meteor will publish that cursor's documents. You can also return an array of Collection.Cursors, in which case Meteor will publish all of the cursors.
So at the moment you can only return a Collection via a cursor (result of a Collection.find()).
To return other data you need to hack into the sockjs stream (the socket library meteor uses to communicate to the server). Be aware this does not guarantee compatibility with future versions of meteor. Sockjs is the library used for meteor to communicate between the server (the wire)
from Publish arbitrary data and automatically update HTML*
client side js
sc = new Meteor._Stream('/sockjs');
sc.on('message', function(payload) {
var msg = JSON.parse(payload);
Session.set('a_random_message', JSON.stringify(msg.data));
});
Template.hello.greeting = function () {
return Session.get('a_random_message');
};
server side js
ss = new Meteor._StreamServer();
ss.register(function (socket) {
var data = {socket: socket.id, connected: new Date()}
var msg = {msg: 'data', data: data};
// Send message to all sockets (which will be set in the Session a_random_message of the client
_.each(ss.all_sockets(), function(socket) {
socket.send(JSON.stringify(msg));
});
});
You can also look at Meteor Streams too. See below.
assume you have added meteor streams via atmosphere - mrt add streams
sc = new Meteor.Stream('hello');
if(Meteor.isServer) {
Meteor.setInterval(function() {
sc.emit('a_random_message', 'Random Message: ' + Random.id());
}, 2000);
Meteor.permissions.read(function() { return true });
}
if(Meteor.isClient) {
sc.on('a_random_message', function(message) {
Session.set('a_random_message', message);
});
Template.hello.greeting = function () {
return Session.get('a_random_message');
};
}

Resources