How come this isn't working Sync/Async issues with Meteor.methods - meteor

This is weird but when I call a external function from Meteor.method function it will always return undefined in the client I tried Meteor.wrapAsync but I think I'm doing something wrong. Here is my code:
var demoFunction = function () {
//database operations
var user = this.userId;
if (!user)
return;
var count = Users.aggregate([
{ $group: {_id: null, count: {$sum: 1}} }
]);
if (count[0] && count[0].count)
return count[0].count;
return 0;
}
Meteor.methods({
// NOT WORKING, How can I make this work?
methodDemo: function () {
var result = demoFunction ();
return result;
},
// Works
methodDemo2: function () {
//database operations
var user = this.userId;
if (!user)
return;
var count = Users.aggregate([
{ $group: {_id: null, count: {$sum: 1}} }
]);
if (count[0] && count[0].count)
return count[0].count;
return 0;
}
});
// Call from client
Meteor.call("methodDemo", function (err, res) { });
calling external functions doesn't work the same way if I put the code inside the meteor method why?

Try using Meteor.userId() in your function instead of this.userId. I think you are loosing the value of this when calling your function causing it to exit early.

Since you declared the function with a var it is scoped outside of methodDemo().
You could declare the function globally by removing var or move the demoFunction() code into methodDemo().

Related

returning embedded document from collection find

This Meteor code tries to return a cursor to the embedded documents referenced by the field data, then checks if it exists (because some times it does not exist in ActiveTaskCol) before returning this template helper method.
added later
The expected returned cursor will be used in the html {{#each data}} for more work hence the use of .find instead of .findOne.
The problem is that the if statement evaluates to true even though there is no data field in the ActiveTaskCol, I also tried obj.count() > 0 which also true even though "data" field does not exist in the collection.
How can I fix this? Thanks
Template.index.helpers({
taskInputs: function () {
var ready = Meteor.subscribe('inputsCol').ready();
var data = InputsCol.find({});
var selectedTask = Session.get('taskSelected');
var obj = ActiveTaskCol.find({action: selectedTask}, {field: {data: 1}});
if (typeof obj != 'undefined') { //<-always true --------------
return {items: obj};
} else {
return {items: data, ready: ready};
}
}
});
It is always true because, you are using find, which returns a cursor. Instead, you should use findOne, so that, it will return document or undefined, if there is no such document. I also suggest, you use obj, which checks for falsy values like undefined, null, false instead of typeof obj != 'undefined'
Template.index.helpers({
taskInputs: function () {
var ready = Meteor.subscribe('inputsCol').ready();
var data = InputsCol.find({});
var selectedTask = Session.get('taskSelected');
var obj = ActiveTaskCol.findOne({action: selectedTask}, {field: {data: 1}});
if (obj) {
return {items: obj};
} else {
return {items: data, ready: ready};
}
}
});
Update:
Based on your comments, you can use obj.count() to check whether there are documents matching your criteria.
Template.index.helpers({
taskInputs: function () {
var ready = Meteor.subscribe('inputsCol').ready();
var data = InputsCol.find({});
var selectedTask = Session.get('taskSelected');
var obj = ActiveTaskCol.find({action: selectedTask}, {field: {data: 1}});
if (obj.count() > 0) {
return {items: obj};
} else {
return {items: data, ready: ready};
}
}
});
Update 2
Template.index.helpers({
taskInputs: function () {
var ready = Meteor.subscribe('inputsCol').ready();
var data = InputsCol.find({});
var selectedTask = Session.get('taskSelected');
var obj = ActiveTaskCol.find({
action: selectedTask,
data: { $exists: true }
}, {
field: {data: 1}
});
if (obj.count() > 0) {
return {items: obj};
} else {
return {items: data, ready: ready};
}
}
});

Meteor getting values from Async function

I am having trouble with getting return value from wrapAsync function in meteor. Below is my code
Template.greet.helpers({
greet : function () {
var convertAsyncToSync = Meteor.wrapAsync( HTTP.get );
resultOfAsyncToSync = convertAsyncToSync('http://www.demo.com/api/greet', {} );
console.log(resultOfAsyncToSync);
return resultOfAsyncToSync;
}
});
I get undefined value in console.
try
Template.greet.onCreated(function(){
this.apiResult = new ReactiveVar(null);
})
Template.greet.helpers({
greet : function () {
var t = Template.instance();
HTTP.get('http://www.demo.com/api/greet', {}, function(e,r){
//process response and save it in reactivevar
t.apiResult.set(r.data);
});
return t.apiResult.get();
}
});
don't forget to add package meteor add reactive-var
EDIT
Template.greet.onRendered(function(){
var t = Template.instance();
HTTP.get('http://www.demo.com/api/greet', {}, function(e,r){
//process response and save it in reactivevar
t.apiResult.set(r.data);
});
})
Template.greet.helpers({
greet : function () {
var t = Template.instance();
return t.apiResult.get();
}
});

Get value returned from another method

In a Template helper, is it possible to get from a method a value returned by another method?
In example
Template.postsList.helpers({
posts: function () {
return Posts.find({});
},
nextPath: function () {
// how to return here the number of posts from the query
// in the posts method?
}
});
You can just refactor the code so you have a shared way to obtain the posts cursor:
var postsCursor = function() {
return Posts.find();
};
Template.postsList.helpers
posts: postsCursor,
nextPath: function () {
var count = postsCursor().count();
// do something with count
}
});

Multiple Data Contexts in router - Meteor

I'm building a meteor app and on one route I'm adding multiple data context like so -
this.route('orgPage', {
path: '/org/:title',
data: {
orgs: function () {Orgs.findOne(this.params._id)},
projects: function() {Meteor.subscribe('projects', this.params._id)}
}
The only problem is that when I try to access this data in my templates js file, I can't access the _id or any of the attributes of orgs.
I've tried several approaches, but it always returns undefined. If I use a single data context, it works perfectly. Here is the function that doesn't function properly -
Template.orgPage.events({
'click #newProject': function(e) {
$('#npModal').modal();
},
'submit #npModal form': function(e, template) {
e.preventDefault();
if(!$(e.target).find('[name=newTitle]').val()) {
var projectTitle = 'Untitled'
} else {
var projectTitle = $(e.target).find('[name=newTitle]').val()
}
var theid = this._id;
var newProject = {
title: projectTitle,
organization: theid
}
Meteor.call('project', newProject, function(error, id) {
if (error)
return alert(error.reason);
$('#npModal').modal('hide');
$('#npModal').on('hidden.bs.modal', function (e) {
Router.go('newFields', {});
})
});
});
Anyone have any ideas? Thanks!!
You have missed a return statement. function () {Orgs.findOne(this.params._id)} should be function () {return Orgs.findOne(this.params._id)}. Further more, this inside this function won't refer to what you want, so you can't use this.params. And why do you subscribe to a subscription as a data context property? Do it in the waitOn function instead.

Firebase on() does not return anything

I have this piece of code using on() to get data from Firebase, inside on() I create object which I want to send out of function for future use - using return, but it seems it doesn't return anything.
So question is how can I make it right?
postsRef.on('value', function(snapshot) {
if (snapshot.val() === null) {
var allPosts = false,
numberOfPosts = 0;
}
else {
var allPosts = snapshot.val(),
numberOfPosts = Object.size(allPosts);
}
var postsData = {
content: allPosts,
count: numberOfPosts
};
return postsData;
});
The callback function is called asynchronously (some time in the future). So by the time it is invoked, postsRef.on(...) has already returned and any code immediately after it will have run.
For example, this might be tempting, but would not work:
var postsData;
postsRef.on('value', function(snapshot) {
postsData = snapshot.val();
});
console.log(postsData); // postsData hasn't been set yet!
So there are a few different ways to tackle this. The best answer will depend on preference and code structure:
Move the logic accessing postsData into the callback
postsRef.on('value', function(snapshot) {
postsData = snapshot.val();
console.log(postsData);
});
Call another function when the callback is invoked
function logResults(postsData) {
console.log(postsData);
}
postsRef.on('value', function(snapshot) {
logResults(snapshot.val());
});
Trigger an event
function Observable() {
this.listeners = [];
}
Observable.prototype = {
monitorValue: function( postsRef ) {
var self = this;
postsRef.on('value', function(snapshot) {
self._notifyListeners(postsRef);
});
},
listen: function( callback ) {
this.listeners.push(callback);
},
_notifyListeners: function(data) {
this.listeners.forEach(function(cb) {
cb(data);
}
}
};
function logEvent( data ) {
console.log(data);
}
var observable = new Observable();
observable.listen( logEvent );
observable.monitorValue( /* postsRef goes here */ );

Resources