how to use Collection.find() inside route action of Meteor js - meteor

I have a peice of code;
Router.configure({
layoutTemplate: 'master_layout'
});
Router.map(function(){
this.route('generatePDF', {
path: '/pdf',
where: 'server',
action: function() {
console.log(voters.findOne().fetch());
var voters = voters.find();
....
}
});
How can I use any given collection inside action of routes.
i get error as below;
W20160510-20:19:29.909(5.5)? (STDERR) TypeError: Cannot call method 'findOne' of undefined
W20160510-20:19:29.910(5.5)? (STDERR) at [object Object].action (lib/routes.js:40:29)
W20160510-20:19:29.910(5.5)? (STDERR) at boundNext (packages/iron_middleware-stack/lib/middleware_stack.js:251:1)

Try this:
action: function () {
this.render('someTemplate',{
data: function(){
return Voters.find()
}
});
}

You've got multiple errors in your code.
Firstly, voters is undefined in the console.log line (as your error log says).
Secondly, Voters.findOne() returns a single document (assuming you have a collection called Voters). You can't call fetch on a document.
You can call fetch on a cursor. For example, Voters.find().fetch() would be fine.
Hope that helps

Related

Undefined exception when running meteor subscribe from angular

My angular controller looks like this:
angular.module("campos").controller("HomeCtrl", ['$scope', '$meteor', '$rootScope', '$state', '$modal',
function ($scope, $meteor, $rootScope, $state, $modal) {
// $scope.users = $meteor.collection(Meteor.users, false).subscribe('users');
$meteor.autorun($scope, function () {
$scope.$meteorSubscribe('myOrgnization', 'crown').then(function () {
$scope.organization.forEach(function (org) {
console.log(org._id);
});
},
function (error) {
console.log(error);
});
});
$scope.organization = $meteor.collection(function(){
return Organizations.find({});
});
}
]);
The server code looks like :
Meteor.publish('myOrgnization', function(org){
return Organizations.find({
'code' : org
});
});
The client controller finished properly, from the console I can get the the record id properly. However, I got an exception thrown out:
TypeError: undefined is not a function
at http://localhost:8026/packages/urigo_angular.js?de756130fe1ce5aaa41d3967997c1b2090bcdd1b:390:12
at Array.forEach (native)
at Function._.each._.forEach (http://localhost:8026/packages/underscore.js?46eaedbdeb6e71c82af1b16f51c7da4127d6f285:149:11)
at diffArray (http://localhost:8026/packages/urigo_angular.js?de756130fe1ce5aaa41d3967997c1b2090bcdd1b:388:5)
at updateCollection (http://localhost:8026/packages/urigo_angular.js?de756130fe1ce5aaa41d3967997c1b2090bcdd1b:1310:3)
at http://localhost:8026/packages/urigo_angular.js?de756130fe1ce5aaa41d3967997c1b2090bcdd1b:1154:11
at http://localhost:8026/packages/angular_angular.js?feeaf4750c9fd3ceafa9f712f99a21ee6fef9b41:17819:31
at completeOutstandingRequest (http://localhost:8026/packages/angular_angular.js?feeaf4750c9fd3ceafa9f712f99a21ee6fef9b41:5529:10)
at http://localhost:8026/packages/angular_angular.js?feeaf4750c9fd3ceafa9f712f99a21ee6fef9b41:5806:7
home.ng.js:8 dPmZoCeJ9YbKxKA4u
It seems coming from angular defer, but I think I am following the subscribe syntax properly ? even I change it to use $meter.subscribe, it throws the same exception.
Any help will be much appreciated.
Thanks in advance.
You should assign the $scope collection after the promise returns:
$scope.$meteorSubscribe('myOrgnization', 'crown').then(function () {
$scope.organization = $scope.$meteorCollection(function(){
return Organizations.find({});
});
});
I would also suggest passing an object for your publish arguments:
$scope.$meteorSubscribe('myOrginization', {arg1: 'crown'}).then(...)
Then of course on the server you would get:
Meteor.publish('myOrgnization', function(org){
return Organizations.find({
'code' : org.arg1
});
});

Meteor.publish() throw an exception in defer callback

I found this error in the server console:
Exception in defer callback: TypeError: undefined is not a function
at packages/ddp/livedata_server.js:1054:1
at Array.forEach (native)
at Function..each..forEach (packages/underscore/underscore.js:105:1)
at [object Object]._.extend._callStopCallbacks (packages/ddp/livedata_server.js:1053:1)
at [object Object]._.extend._deactivate (packages/ddp/livedata_server.js:1043:1)
at packages/ddp/livedata_server.js:803:1
at Function..each..forEach (packages/underscore/underscore.js:113:1)
at [object Object]._.extend._deactivateAllSubscriptions (packages/ddp/livedata_server.js:802:1)
at packages/ddp/livedata_server.js:444:1
at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
And here the code I use:
/* Source: http://phucnguyen.info/blog/how-to-publish-to-a-client-only-collection-in-meteor/ */
var subs = {};
Meteor.publish(
// THROW AN 'EXCEPTION IN DERFER CALLBACK: ...'
'helperPublication',
function () {
var subscription = this;
subs[subscription._session.id] = subscription;
Datasets.find().map(function (dataset) {
subscription.added(
'subdatasets',
dataset._id,
{
name: dataset.name,
data: [], // To avoid "Uncaught TypeError: Cannot read property 'length' of undefined" error on load
peaks: [] // Idem
}
)
});
subscription.onStop();
subscription.ready()
});
You can find the whole app in the following meteorpad: http://meteorpad.com/pad/6NDneym2qEW7pF9JM/ClearChrom
Ok, So with that info; I think the best way to go about doing this is to have separate collection for that data. Because then you can easily change how much data should be displayed. The publication for that collection could look like this:
Meteor.publish('data', function publishData (limit) {
return DataCollection.find({}, {
fields: {
name: 1,
data: 1,
peaks: 1
},
limit: limit
})
});
Note that the callback of the publication takes an argument limit. You can now subscribe to it like this:
Meteor.subscribe('data', 3)
And whenever you need more data you can just:
Meteor.subscribe('data', 6)
So this solution is reactive and very clean (in my opinion at least).
I also checked your existing script:
var subs = {};
Meteor.publish(
'helperPublication',
function (limit) {
var subscription = this;
subs[subscription._session.id] = subscription;
// I'd use forEach here, because you're not modifying the document
Datasets.find().forEach(function (doc) {
subscription.added(
'subdatasets',
doc._id,
{
name: doc.name,
// Whith the slice function you can get a subset of the data array
data: doc.data.slice(0, limit),
peaks: doc.peaks
}
)
});
// Calling `subscription.onStop` without an argument doesn't do anything
// Except maybe through an error
subscription.onStop(function () {
// clean the subscription from subs again
delete subs[subscription._session.id];
});
// This shouldn't be necessary.
// subscription.ready()
});
There are some issues with this still. For one thing I'd advise you to try avoiding meteor attributes with an underscore in front. They might be removed or changed in future releases.

Setting data that belongs to a User in iron router

Router.route('/settings', {
name: 'settings',
data: function() {
return Settings.findOne({userId: Meteor.user()._id});
}
});
It's showing an error in the browser:
Uncaught TypeError: Cannot read property '_id' of undefined
Any suggestions on how to grab the settings record for a logged in user?
Meteor logging in process usually takes a few ms to get ready, meanwhile Meteor.user() will return undefined and the first execution of your route data method will fail.
You can use Meteor.userId() to avoid this from happening until the user is connected for real.
Router.route('/settings', {
name: 'settings',
data: function() {
return Settings.findOne({
userId: Meteor.userId()
});
}
});

"Cannot read property 'username' of undefined" in a Meteor Route?

The page still renders as it should, but this appears in my console log.
Exception in callback of async function: TypeError: Cannot read
property 'username' of undefined
at null. (http://localhost:3000/router.js?39194109cc7760190c519a386d66c807ba19230c:48:9)
at boundNext (http://localhost:3000/packages/iron_middleware-stack.js?0e0f6983a838a6516556b08e62894f89720e2c44:424:31)
at Meteor.bindEnvironment (http://localhost:3000/packages/meteor.js?43b7958c1598803e94014f27f5f622b0bddc0aaf:983:22)
at onRerun (http://localhost:3000/packages/iron_router.js?a427868585af16bb88b7c9996b2449aebb8dbf51:520:9)
at boundNext (http://localhost:3000/packages/iron_middleware-stack.js?0e0f6983a838a6516556b08e62894f89720e2c44:424:31)
at Meteor.bindEnvironment (http://localhost:3000/packages/meteor.js?43b7958c1598803e94014f27f5f622b0bddc0aaf:983:22)
at onRun (http://localhost:3000/packages/iron_router.js?a427868585af16bb88b7c9996b2449aebb8dbf51:505:11)
at boundNext (http://localhost:3000/packages/iron_middleware-stack.js?0e0f6983a838a6516556b08e62894f89720e2c44:424:31)
at Meteor.bindEnvironment (http://localhost:3000/packages/meteor.js?43b7958c1598803e94014f27f5f622b0bddc0aaf:983:22)
at dispatch (http://localhost:3000/packages/iron_middleware-stack.js?0e0f6983a838a6516556b08e62894f89720e2c44:448:3)
Which points to the line indicated below:
var OnBeforeActions = {
loginRequired: function() {
if (!Meteor.userId()) {
this.render('hello');
} else {
this.next();
}
}
};
Router.onBeforeAction(OnBeforeActions.loginRequired, {
only: ['home']
});
Router.route('/', function() {
// this.render('homepage');
Router.go('/users/' + Meteor.userId());
});
Router.route('/users/:user_id', function() {
this.render('home', {
data: {
username: Meteor.users.findOne({
_id: this.params.user_id
}).username, // THIS LINE HERE
}
});
});
The idea is to redirect the user to his page if he is already logged in - and it appears to work as it should, but why am I getting this?
When the browser loads initially there will not be any data available (all the collections will be empty - until they are downloaded. Thus the result of the query Meteor.users.findOne({_id: this.params.user_id}) will be undefined.
This is the reason you can't read username out of undefined.
Since the query will re-run/it is reactive you just need to take account when it is null and it will sort itself out. user.username is only read if user is not null:
Router.route('/users/:user_id', function() {
var user = Meteor.users.findOne({_id :this.params.user_id});
this.render('home', {
data: {
username: user && user.username
}
});
});

Meteor iron-route onBeforeAction

I have this simple Iron-router route in my Meteor application which I use whenever any user need to logout of the app, although whenever I call this route I get the following error. Can someone please tell me what I am doing wrong/ missing here? Thanks
On a minor note, Meteor.logout doesn't return any error
Router.route('/logout', function(){
Meteor.logout(function(err){
if(err){
console.log('Error Logging out: '+ err);
}
this.redirect('home');
});
});
Error:
Route dispatch never rendered. Did you forget to call this.next() in an onBeforeAction?
Exception in delivering result of invoking 'logout': TypeError: undefined is not a function
at http://localhost:3000/both/router/routes.js?8871acf5e06150f7af89862f68c245a05fe13db8:110:12
at http://localhost:3000/packages/accounts-base.js?7c29db5c21a76726509bb6bb2a68a2b4b1ecf657:674:19
Scope in Meteor.logout callback is not the same scope as in Router.route callback. That's why you need to assign Router.route's scope to variable self and then use it inside Meteor.logout callback.
Router.route('/logout', function(){
var self = this;
Meteor.logout(function(err){
if(err){
console.log('Error Logging out: '+ err);
}
self.redirect('home');
});
});

Resources