Correct way to write helper functions in Meteor - meteor

I'm new to Meteor and I'm trying to figure out the difference between writing:
Template.main.folks =
function () {
return Clients.find();
};
and writing it using "helpers":
Template.main.helpers({
folks: function () {
return Clients.find();
});
Are they the same thing?

Nothing difference, but the first one is gonna be removed soon. If you do that, it still run, but will give you the deprecated warning

Related

Sinon JS Stubbing/Mocking undefined properties

I am hoping someone will be able to help me out with a small issue. I am trying to stub out an undefined property that lives inside a function and return a known value, I am trying this with a simple test case:
var self = this;
self.test = function() {
return person.myId();
};
if (typeof module !== "undefined" && module.hasOwnProperty("exports")) {
module.exports = self;
}
return self;
what I have tried to do is:
it('Basic stub test', function() {
sinon.stub(code, 'person.myId').return("1234");
assert(code.test(), "1234");
});
I had hoped the above would stub any calls made to person.myId(), however, I just get any error saying: Cannot stub non-existent own property person.myId.
We use our own software that handles dependency injection (e.g. during runtime in our software person is made available) but we are attempting to write isolated unit tests outside of the software, hence the necessity for stubbing out the missing dependencies.
Has anyone attempted this kind of thing before? Am I trying to do something that isn't possible?
Thank you for any help/support anyone can provide.
Sam
I'm not sure what kind of magic the dependency injection software does, so here is a middle ground answer.
It's less than ideal because it tends to be a code smell if you're changing the code you want to test, although it fits your specific question.
I'm also assuming you're using something like mocha that provides the before & afterEach functions.
var sandbox = sinon.createSandbox();
before(function () {
var person = {
myId: () => console.log('myId no op'),
};
code.person = person;
}
it('Basic stub test', function() {
sandbox.stub(code.person, 'myId').returns('1234');
assert(code.test(), '1234');
});
afterEach(function () {
sandbox.restore();
});
Documentation Link: http://sinonjs.org/releases/v4.1.3/sandbox/
(Although the use of sandbox isn't strictly required here)

Meteor startup return function

I have seen quite a few times that the startup function of Meteor returns a function. What does it mean? Where is the function returned? Who is using the returned function?
Meteor.startup(function () {
Init();
return Tracker.autorun(function () {
const userId = Meteor.userId();
if (!userId) {
//do something
}
});
});
I have not seen startup returning a function, and I have never used it. It wont break and will work all the same, but I do not know why it is done in this example.
It is also strange that it is returning an autorun function... both startup and autorun are client api event handler hooks ... no one should be listening to the results of the function calls becuase these calls are not made by the app but rather the meteor platform, their function is to run code at either startup, or as a separate reactive fiber (autorun).

How to get a published collection's total count, regardless of a specified limit, on the client?

I'm using the meteor-paginated-subscription package in my app. On the server, my publication looks like this:
Meteor.publish("posts", function(limit) {
return Posts.find({}, {
limit: limit
});
});
And on the client:
this.subscriptionHandle = Meteor.subscribeWithPagination("posts", 10);
Template.post_list.events = {
'click #load_more': function(event, template) {
template.subscriptionHandle.loadNextPage();
}
};
This works well, but I'd like to hide the #load_more button if all the data is loaded on the client, using a helper like this:
Template.post_list.allPostsLoaded = function () {
allPostsLoaded = Posts.find().count() <= this.subscriptionHandle.loaded();
Session.set('allPostsLoaded', allPostsLoaded);
return allPostsLoaded;
};
The problem is that Posts.find().count() is returning the number of documents loaded on the client, not the number available on the server.
I've looked through the Telescope project, which also uses the meteor-paginated-subscription package, and I see code that does what I want to do:
allPostsLoaded: function(){
allPostsLoaded = this.fetch().length < this.loaded();
Session.set('allPostsLoaded', allPostsLoaded);
return allPostsLoaded;
}
But I'm not sure if it's actually working. Porting their code into mine does not work.
Finally, it does look like Mongo supports what I want to do. The docs say that, by default, cursor.count() ignores the effects of limit.
Seems like all the pieces are there, but I'm having trouble putting them together.
None of the answers do what you really want becase none provide solution that is reactive.
This package does exactly what you want and also reactive.
publish-counts
I think you can see the demo: counts-by-room in meteor doc
It can help you publish the counts of your posts at server and get it at client
You can simply write this:
// server: publish the current size of your post collection
Meteor.publish("counts-by-room", function () {
var self = this;
var count = 0;
var initializing = true;
var handle = Posts.find().observeChanges({
added: function (id) {
count++;
if (!initializing)
self.changed("counts", 'postCounts', {count: count});
},
removed: function (id) {
count--;
self.changed("counts", postCounts, {count: count});
}
});
initializing = false;
self.added("counts", 'postCounts', {count: count});
self.ready();
self.onStop(function () {
handle.stop();
});
});
// client: declare collection to hold count object
Counts = new Mongo.Collection("counts");
// client: subscribe to the count for posts
Tracker.autorun(function () {
Meteor.subscribe("postCounts");
});
// client: simply use findOne, you can get the count object
Counts.findOne()
The idea of sub.loaded() is to help you with exactly this problem.
Posts.count() isn't going to return the right thing because, as you've guessed, on the client, Meteor has no way of knowing the real number of posts that live on the server. But what the client knows is how many posts it's tried to load. That's what that .loaded() tells you, and is why the line this.fetch().length < this.loaded() will tell you if there are more posts on the server or not.
What I would do is write a Meteor server side method that retrieves the count like so:
Meteor.methods({
getPostsCount: function () {
return Posts.find().count();
}
});
Then call it on the client, in observe to make it reactive:
function updatePostCount() {
Meteor.call('getPostsCount', function (err, count) {
Session.set('postCount', count);
});
}
Posts.find().observe({
added: updatePostCount,
removed: updatePostCount
});
Although this question is old, I thought I would provide an answer that ended up working for me. I did not create the solution, I found the basis for it here (so credit where credit is due): Discover Meteor
Anyway, in my case I was trying to get "size" of the database from client side, so I can determine when to hide the "load more" -button. I was using template level subscriptions. Oh and for this solution to work, you need to add reactive-var -package. Here is my (in short):
/*on the server we define the method which returns
the number of posts in total in the database*/
if(Meteor.isServer){
Meteor.methods({
postsTotal: function() {
return PostsCollection.find().count();
}
});
}
/*In the client side we first create the reactive variable*/
if(Meteor.isClient){
Template.Posts.onCreated(function() {
var self = this;
self.totalPosts = new ReactiveVar();
});
/*then in my case, when the user clicks the load more -button,
we call the postsTotal-method and set the returned value as
the value of the totalPosts-reactive variable*/
Template.Posts.events({
'click .load-more': function (event, instance){
Meteor.call('postsTotal', function(error, result){
instance.totalPosts.set(result);
});
}
});
}
Hope this helps someone (I recommend checking the link first). For template level subscriptions, I used this as my guide Discover Meteor - template level subscriptions. This was my first stacked-post and I am just learning Meteor, so please have mercy...:D
Ouch this post is old, anyway maybe it will help someone.
I had exactly the same issue. I managed to solve it with 2 simple lines...
Remember the :
handle = Meteor.subscribeWithPagination('posts', 10);
Well I used in client handle.loaded() and Posts.find().count(). Because when they are different it means that all the posts are loaded. So here is my code :
"click #nextPosts":function(event){
event.preventDefault();
handle.loadNextPage();
if(handle.loaded()!=Posts.find().count()){
$("#nextPosts").fadeOut();
}
}
I had the same problem, and using the publish-counts package didn't work with the subs-manager package. I created a package that can set a reactive server-to-client session, and keep the document count in this session. You can find an example here:
https://github.com/auweb/server-session/#getting-document-count-on-the-client-before-limit-is-applied
I'm doing something like this:
On cliente
Template.postCount.posts = function() {
return Posts.find();
};
Then you create a template:
<template name="postCount">
{{posts.count}}
</template>
Then, whatever you want to show the counter: {{> postCount}}
Much easier than any solution i have seen.

Facebook API Javascript Not Defined

This is a fairly general problem I am having here, so I figured I would ask, hopefully someone can help me out.
I have a flex app using the facebook js bridge to log in, and I am trying to pass the users name back to the app, but I am coming across the thing that I will explain after the code:
function getFriends() {
var nameOfPlayer = "";
FB.api('/me', function(response) {
nameOfPlayer = response.name;
});
return nameOfPlayer;
}
If I have my flex app print nameOfPlayer, it returns undefined, same as if I do an alert with nameOfPlayer, but if I do an alert inside of the FB.api call for nameOfPlayer, then it will pop up with my name, but it still won't return name. I tried having it return a general string, and that works, so it is passing the information over, it just isn't saving to the variable. Any idea how to fix this? This is probably very convoluted, so if I need to clarify anything let me know. Thanks in advance for any help you can give me :)
You should be doing this in an event-driven way. Some pseudo-code is written below to get you started.
var yourFacebookAPIClass = new yourFacebookAPIClass();
yourFacebookAPIClass.addEventListener(Event.UserCallComplete, function(ev){
var nameOfPlayer = SomeParser.ParseData(ev);
someFunctionThatUsesYourVar(nameOfPlayer);
});
yourFacebookAPIClass.getNameOfPlayer();
In your facebook api class:
function getNameOfPlayer(){
makeTheApiCallHere();
}
The function you're defining inside of the FB.api call is actually a callback function which means it's called asynchronously. So the line of code after the api call (the return statement) will execute right away without waiting for Facebook to return a response. The callback function, on the other hand, will wait for Facebook to response, in fact that's what it's designed for. You'd be better off doing all your logic that depends on the nameOfPlayer inside of that callback function.
If you definitely have to return a nameOfPlayer variable the way it's written you'd need to tell your code to wait for nameOfPlayer to be defined:
function getFriends() {
var nameOfPlayer = "";
FB.api('/me', function(response) {
nameOfPlayer = response.name;
});
while(typeof nameOfPlayer === "undefined" || nameOfPlayer == "") {}
return nameOfPlayer;
}
But I really would not recommend this because your app will freeze while it waits for a response. You'd be better off doing everything inside of your callback function instead of returning something.
Good luck! :)

What is the best control flow module for node.js?

I've used caolan's async module which is very good, however tracking errors and the varying way of passing data through for control flow causes development to sometimes be very difficult.
I would like to know if there are any better options, or what is currently being used in production environments.
Thanks for reading.
I use async as well. To help tracking errors it's recommended you name your functions, instead of having loads of anonymous functions:
async.series([
function doSomething() {...},
function doSomethingElse() {...},
function finish() {...}
]);
This way you'll get more helpful information in stack traces.
...however tracking errors and the varying way of passing data through for control flow causes development to sometimes be very difficult.
I've recently created a simple abstraction named "wait.for" to call async functions in sync mode (based on Fibers): https://github.com/luciotato/waitfor
Using wait.for, you can use 'try/catch' while still calling async functions, and you keep function scope (no closures needed). Example:
function inAFiber(param){
try{
var data= wait.for(fs.readFile,'someFile'); //async function
var result = wait.for(doSomethingElse,data,param); //another async function
otherFunction(result);
}
catch(e) {
//here you catch if some of the "waited.for"
// async functions returned "err" in callback
// or if otherFunction throws
};
see the examples at https://github.com/luciotato/waitfor
Sometimes it is hard to put all the functions in an array. When you have an array of objects and want to do something for each object, I use something like the example below.
read more in: http://coppieters.blogspot.be/2013/03/iterator-for-async-nodejs-operations.html
var list = [1, 2, 3, 4, 5];
var sum = 0;
Application.each(list, function forEachNumber(done) {
sum += this;
// next statement most often called as callback in an async operation
// file, network or database stuff
done(); // pass an error if something went wrong and automatically end here
}, function whenDone(err) {
if (err)
console.log("error: " + err);
else
console.log("sum = " + sum);
});
I name the functions, because it is easier to debug (and easier to read)

Resources