Meteor.User does not load with all fields on initial load - meteor

I have added an additional field on Meteor.Users collection called usertype. In Iron-router I am returning the user object if user is logged in. Now in my template I need to check if this usertype field is present else, I direct the user to user registrations screen.
What is happening here is that even though I have the usertype field in my publish function, the user object is not returned with this field initially. It only shows up after 2-3 object loads. And this confuses the template loading logic, as this field is not found on initial load, but when infact the field is present.
DashboardController = RouteController.extend({
template: 'dashboard',
subscriptions: function() {
this.userProfileSub = Meteor.subscribe('singleUser', this.myId());
},
myId: function() {
var userId = Meteor.userId();
if(!userId)
{ userId = ''; }
return userId;
},
user: function() {
return Meteor.users.findOne(this.myId());
},
data: function() {
var user = this.user();
console.log(user);
if(user)
{
return {
user: this.user(),
ready: this.userProfileSub,
};
}
}
});
Here is the publish method:
Meteor.publish('singleUser', function(id) {
check(id, String);
return Meteor.users.find({_id:id}, {fields: { emails: 1,
profile: 1,
usertype: 1,
"services.facebook.id": 1,
"services.facebook.email": 1,
"services.twitter.screenName": 1,
"services.twitter.profile_image_url": 1,
"services.google.email": 1,
"services.google.picture": 1}});
});
EDIT
As answer given below, if the subscription is moved inside the waitOn block it should wait for the subscription to load completely.
waitOn: function() {
this.userProfileSub = Meteor.subscribe('singleUser', this.myId());
return [this.userProfileSub];
},
But now when I try to wait for multiple subscriptions to load in the wait array, it apparently is not waiting for all of them. I still get empty array. Even though I check in the action block. I can find the data later from my console.
waitOn: function() {
return [
Meteor.subscribe('singleUser', this.myId()),
Meteor.subscribe('singleAgentByUserId', this.myId()),
Meteor.subscribe('singleClientByUserId', this.myId())];
},
action: function () {
// this.ready() is true if all items returned from waitOn are ready
if (this.ready())
{
this.render();
}
else
this.render('Loading');
},

Update EDITED (See revision history for much different version due to original question)
Try:
waitOn: function() {
return [
Meteor.subscribe('singleUser', Meteor.userId()),
Meteor.subscribe('singleAgentByUserId', Meteor.userId()),
Meteor.subscribe('singleClientByUserId', Meteor.userId()];
},
loadingTemplate: "loading",
action: function () {
this.render('dashboard');
}

Related

Publish users using id from a different collection

I'm trying to access the userIds stored in a collection and then use them to publish the details of all of the meteor.users. My publish function doesn't isn't return anything?
Meteor.publish('allUsersWithOffers', function () {
var user = Offers.find({}, {fields: {"UserId": 1}});
return Meteor.users.find({_id: user});
});
Give this a try:
Meteor.publish('allUsersWithOffers', function () {
var offers = Offers.find({}, { fields: { UserId: 1 } }).fetch();
var ids = _.pluck(offers, 'UserId');
// This is critical - you must limit the fields returned from
// the users collection! Update this as needed.
options = { fields: { username: 1, emails: 1 } };
return Meteor.users.find({ _id: { $in: ids } }, options);
});
find returns a cursor - you need to call fetch to actually get the documents.

Why isn't my subscription adding data to Meteor.user()?

I'm publishing this user information (as a test FYI, not going to reveal all this information in production)
Meteor.publish('user.private', function userPrivate() {
if (!this.userId) {
return this.ready();
}
return Meteor.users.find({
_id: this.userId
}, {
fields: {
'services.microsoft': 1,
'services.google': 1
}
});
});
I'm subscribing like this:
Template.App_body.onCreated(function appBodyOnCreated() {
this.subscribe('user.private');
});
I've confirmed that this exact query works and returns data using meteor mongo, yet this information does not appear in the Meteor.user() call on the client. What am I doing wrong?
try changing the publication name to null to make it automatically publish.
Meteor.publish(null, function () {
return Meteor.users.find(this.userId, {
fields: { /** ... fields here */ }
});
});

Subcribe gets more records than server publishes

I am trying to publish all admin users from server
on server something like this:
Meteor.publish("users_with_roles", function (options, role) {
//{fields: {emails: 1, profile: 1}}
Counts.publish(this, 'numberOfUsers', Meteor.users.find({$and:[
{'roles.tripro': {$exists: true}},
{'roles.tripro': role}
]}),
{ noReady: true });
return Meteor.users.find({
$and:[
{'roles.tripro': {$exists: true}},
{'roles.tripro': role}
]
}, options);
});
Then on client side, I am trying to subscribe this:
$meteor.autorun($scope, function() {
$meteor.subscribe('users_with_roles', {
limit: parseInt($scope.getReactively('perPage')),
skip: (parseInt($scope.getReactively('page')) - 1) * parseInt($scope.getReactively('perPage')),
sort: $scope.getReactively('sort'),
fields: {emails: 1, profile: 1}
},'admin').then(function() {
$scope.usersCount = $meteor.object(Counts ,'numberOfUsers', false);
console.log('user counter:' + $scope.usersCount.count);
$scope.users.forEach( function (user) {
// user.onClicked = function () {
// //$state.go('userProfile', {userId: user._id});
// };
console.log(user._id);
});
},
function(error)
{
console.log(error);
}
);
});
$scope.users = $meteor.collection(function() {
console.log('looking for role: ' + role);
return Meteor.users.find({}, {
//sort : $scope.getReactively('sort')
});
});
However, from the logging, it appears that the client side received all users , but from the logging on server side, it does give correct result.
What am I missing here?
A couple things to think about here.
When you request users you will always have "you". So if the user you are logged into is not an admin, it will still show up in the collection.
Because you are using $meteor.subscribe instead of $scope.$meteorSubscribe you are not clearing the subscription when the scope is destroyed so it's possible that it's mixing with other subscriptions on the client side from other scopes.

Unable to pass result to router after calling Meteor.methods

I encounter an error using Meteor. I call an Method.method.
Template.WelcomeTemplate.events({
'click #btn-findgame': function(e) {
e.preventDefault();
console.log('clicked find game button');
Meteor.call('allocateGame', function(error, id) {
if (error) {
alert(error.reason);
} if (id) {
Router.go('gameRoom', {_id: id})
}
})
}
})
With my Method, I check if there is an room available, create one when the isn't otherwise join. And return the ID of this room.
Meteor.methods({
allocateGame: function () {
console.log('allocateGame method called')
var user = Meteor.user();
// find game where one player is in the room
var gameWaiting = Games.findOne({players: {$size: 1}})
if (!gameWaiting) {
console.log('no game available, create a new one');
var newGameId = Games.insert({players: [user._id], active: false, finished: false});
GameDetails.insert({gameId: newGameId, gameData: []});
return newGameId
} else {
if (_.contains(gameWaiting.players, user._id)) {
console.log('Cannot play against yourself sir')
} else {
console.log('Joining game');
Games.update({_id: gameWaiting._id}, {
$set: {active: true},
$push: {players: user._id}
});
return gameWaiting._id;
}
};
}
})
And my Router:
Router.map(function () {
this.route('welcome', {
path: '/',
controller: WelcomeController})
this.route('gameRoom', {
path: '/game/_:id'
})
});
The Error I recieve is:
Exception in delivering result of invoking 'allocateGame': TypeError: Cannot read property 'charAt' of null
at Object.IronLocation.set (http://localhost:3000/packages/iron-router.js?e9fac8016598ea034d4f30de5f0d356a9a24b6c5:1293:12)
And indeed, If I don't return an ID the Routing will continue as normal. However when I return an ID in my WelcomeTemplate an error will occur.
EDIT:
Even thought my MongoDB is updating my MiniMongo DB is empty. There must be a problem with syncing. Any idea where to look?
In the route, you set the path to be '/game/_:id', that is, a parameter with the name id. In your call to Router.go, you pass a parameter with the name _id.
Don't know if this solves your problem, but it's an error.
This kind of embarrassing taking in account how many hours I've spent on fixing this. The error was created because of an error in my routers.js
this.route('gameRoom', {
path: '/game/_:id'
})
Should be:
this.route('gameRoom', {
path: '/game/:_id'
})
Happy coding.

Do Meteor-Roles and Iron-Router play nicely together?

I have a Meteor app with an editor page that should only be accessible to editors. I am using Iron-Router and my Router.map looks like the following. However, this is not working in an odd way. If I provide a link to the editor page, then all is well, but if I try entering the /editor url, then it always redirects to home, even if the user role is correctly set.
(One thing I ruled out was if Meteor.userId() is not set before Roles.userIsInRole is called in before.)
Anyone know why this would be?
Router.map(function() {
...
this.route('editor', {
path: '/editor',
waitOn: function() {
//handle subscriptions
},
data: function() {
//handle data
},
before: function() {
if ( !Roles.userIsInRole(Meteor.userId(), 'editor') ) {
this.redirect('home');
}
}
});
...
});
The Roles package sets up an automatic publication that sends the roles property on the Meteor.users collection. Unfortunately, you can't get a subscription handle for automatic publications, so you'll need to make your own.
Set up a new subscription that publishes the required data of a user, then configure Router to check that the data is ready before showing any page.
eg:
if (Meteor.isServer) {
Meteor.publish("user", function() {
return Meteor.users.find({
_id: this.userId
}, {
fields: {
roles: true
}
});
});
}
if (Meteor.isClient) {
var userData = Meteor.subscribe("user");
Router.before(function() {
if (Meteor.userId() == null) {
this.redirect('login');
return;
}
if (!userData.ready()) {
this.render('logingInLoading');
this.stop();
return;
}
this.next(); // Needed for iron:router v1+
}, {
// be sure to exclude the pages where you don't want this check!
except: ['register', 'login', 'reset-password']
});
}

Resources