What is wrong with my code. Meteor.users.findOne() or Meteor.user.find() only works in Chrome. Does not work in Firefox nor Safari -- Im on a Mac. My error is:
TypeError: Meteor.users.findOne(...) is undefined
I want to have a user profile so upon registration, the profile field is created using Reactjs:
Registration component (Client):
Accounts.createUser({
...
profile: [] //later you'll see why for this.
});
Server:
// We us this to add more fields to a user registration:
Accounts.onCreateUser(function(options, user) {
user['regtype'] = options.regtype,
user['profile'] = options.profile
return user
});
Meteor.publish(null, function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'regtype': 1, 'profile': 1}});
} else {
this.ready();
}
});
The error comes from my Profile.jsx:
...
mixins: [ReactMeteorData],
getMeteorData() {
return {
currentUser: Meteor.user(),
};
},
getInitialState(){
profile = Meteor.users.findOne().profile; // the error is here
return{name: profile.name}
}
...
Strangely if I console.log(Meteor.user.find()) it shows as undefined. But works great in Chrome only. I have not tried MS Edge.
According to meteor docs
The basic Accounts system is in the accounts-base package, but
applications typically include this automatically by adding one of the
login provider packages: accounts-password, accounts-facebook,
accounts-github, accounts-google, accounts-meetup, accounts-twitter,
or accounts-weibo.
So If you have the accounts-base package you'll get the Meteor.user() and Meteor.users() functions. Check your .meteor/packages file for account-base package. Add if it is not listed in there.
Here is my answer to this. I hope others find this very useful. Basically I wish to bind the input fields with user's data (profile fields). Upon user registration, I add a profile field and set it to an empty array: profile: []
I need not to use getInitialState() but instead use getMeteorData(). With same code, I need to move the component's render in a function and render that:
...
renderedComponent(){
let instance = this;
render(<div><input value={instance.data.currentUser.profile.name} /></div>)
},
// we now wait until currentUser is loaded before calling the render function
render(){
return(<div>{this.data.currentUser? this.renderedComponent() : <p>Loading...</p>}</div>)
}
...
To sum up, nothing is wrong with firefox or any part of my code. When working with Meteor and React, this is the best approach.
Related
I have a template that has data getting passed into it through the Iron Router params here, it might be obvious what the template is being designed to do:
lib/routes.js
// custom reset password page for child user
Router.route('/reset-password/child/:_id', {
name: 'reset-child-password',
template: 'childResetPassword',
layoutTemplate: 'appLayout',
data: function() {
return Users.findOne({ _id: this.params._id });
}
});
But, when I try to access this child user data in the template I get errors saying this.data is undefined. or cannot read property 'profile' of undefined. Here are my helpers and template use of the helper.
client/templates/childResetPassword.html
...
<h3>Reset Password for {{childFirstName}}</h3>
<form id='childResetPassword'>
<div class="form-group">
<input type="password" name="new-child-password" class="form-control" value=''>
</div>
...
client/templates/helpers/childResetPassword.js
Template.childResetPassword.helpers({
childFirstName: function() {
console.log("Template helpers:");
console.log(this.data);
return this.data.profile.firstname;
}
});
Any thoughts on how to access the data-context passed with the iron router data callback? Am I using it incorrectly?
UPDATE (STILL NOT ANSWERED): I have verified that this particular user that I am passing into the template data-context is being found and that their profile is populated with a firstname property, and I'm still getting the same error.
Based on another question I found I tried this. I added a Template rendered callback function like this:
client/templates/helpers/childResetPassword.js
Template.childResetPassword.rendered = function() {
console.log(this);
};
I do see this.data containing the correct user object in the browser console, but my this.data.profile.firstname still fails, yet again, with the same console output error. If there something I need to do between the template rendering and the template helper?? SO CONFUSED!!!
You don't have to mention data ... you can just call this.profile.firstname. Your application already understands 'this' as the data object that is returned.
Template.childResetPassword.helpers({
childFirstName: function() {
return this.profile.firstname;
}
});
So, #Joos answer is not wrong, however after a lot more trial and error I found the solution for the meteor project I am working on.
My project (unbeknownst to me until I looked around more) has the meteor package autopublish removed. Therefore in order to access data in my collections I have to be subscribed to them. So the best place I put this subscription line is within my Router.route declaration for this template:
Router.route('/reset-password/child/:_id', {
name: 'reset-child-password',
template: 'childResetPassword',
layoutTemplate: 'appLayout',
waitOn: function() { // this is new new line/option i added to my route
return Meteor.subscribe('users');
},
data: function() {
if (this.ready()) {
var childUser = Users.findOne({_id: this.params._id});
if (childUser)
return childUser;
else
console.error("Child User not found", childUser);
}
else {
this.render("Loading");
}
}
});
So with that being said, if you still have autopublish package in your project and you intending to keep it, then #Joos answer is all you need to do.
However, if you DO intend to remove it, you need my router solution above, combined with making sure that you have published your users collection like this somewhere on the server:
server/publications.js
Meteor.publish("users", function () {
return Meteor.users.find();
});
I'm trying to implement a basic route using Flow Router. But no matter what _id of a collection document I request; I always only get the info about the first document in my collection - 'Requests'.
So here's my route definition in the file /lib/routes.js:
FlowRouter.route('/requests/:reqId', {
subscriptions: function (params, queryParams) {
this.register('theRequest', Meteor.subscribe('singleRequest', params.reqId));
},
action: function (params, queryParams) {
FlowLayout.render('layout', { aside: 'aside', main: 'singleRequest' });
console.log("Yeah! We are on the post:", params.reqId);
},
name: 'aRequest'
});
Here's my helper:
Template.singleRequest.helpers({
getRequest: function () {
return Requests.findOne();
}
});
Here's my server publish:
Meteor.publish('singleRequest', function (reqId) {
return Requests.find({ _id: reqId});
});
And here's the template:
<template name="singleRequest">
{{#if isSubReady 'theRequest'}}
{{#with getRequest}}
<h2>{{_id}}</h2>
<p>{{reqFrom}}</p>
<p>{{reqBy}}</p>
{{/with}}
{{else}}
loading...
{{/if}}
</template>
What am I doing wrong?
Note: In the console, I do see right 'reqId' slug due to the console.log command in the route definition. But I do not see the relevant info for the document which it belongs to.
Thanks!
OK my problem was that I previously had another subscription where I published all the Requests - not just the one with that certain _id. And because I did not create the helper to get only the one with that certain _id; of course server just sent me the very first request.
My solution was only to subscribe to previous subscription and define in the helper to fetch to the request _id:
FlowRouter.route('/requests/:reqId', {
subscriptions: function (params, queryParams) {
this.register('allRequests', Meteor.subscribe('Requests', params.reqId));
},
action: function (params, queryParams) {
FlowLayout.render('layout', { aside: 'aside', main: 'singleRequest' });
console.log("Yeah! We are on the post:", params.reqId);
},
name: 'aRequest'
});
and the helper:
Template.singleRequest.helpers({
getRequest: function () {
var reqId = FlowRouter.getParam("reqId")
return Requests.findOne({_id:reqId});
}
});
For anyone who browses to this question looking for how to get Flow Router to capture and dynamically link to slugs from the db, then call a template page for each item, I made a very simple example app and posted it on here on GitHub.
Hope it will help someone.
I believe your code is correct for what you are trying to do. However, I infer from your direct replication of the code from flow-router that you're pretty new to Meteor. Therefore, I'm willing to take a punt that you still have the autopublish package in your app.
Autopublish pushes all data in your collection to the client. Even without a publish/subscribe call.
You can do two things. To keep autopublish (which will make your development process easier at the start but maybe harder later on), just change your template helper to:
Template.singleRequest.helpers({
getRequest: function () {
return Requests.findOne({ _id: FlowRouter.getParam("reqId")});
}
});
Alternatively (and you will want to do this eventually), go the the command line and type:
meteor remove autopublish
You can read up on the pros and cons of autopublish in lots of places to make your own decision on which option is best for you. However, you should also consider whether or not you want to cache your data in future (e.g. using subsManager) so you may want to change your template helper regardless.
In Meteor.js, how do one generally give different users (say depending on a field role in the users collection, which can have values like admin, users, testers) different versions of the site (both clientside and serverside)?
First, I am using Iron Router for my routing. At some point I may drop it and write my own, at least for this project, as I am not using half of the features, but for now this is what I have.
For roles I am using the alanning:roles package. Again, I could probably write my own, but it does what I need it too for now, so I am happy with it.
Next I have a custom package I wrote. In it I set up a template for signin and signout, with routes etc. I also provide a utility class that provides a function called authenticationRequired. This function will check if the current user is logged in, and if roles are passed in that they have those roles. The code looks like this:
AccountUtils.authenticationRequired = function(router, roles) {
if (!router) {
throw new Meteor.Error(500, 'Router is a required parameter');
}
if (!Meteor.loggingIn()) {
var currUser = Meteor.user();
if (currUser) {
if (roles) {
if (!Roles.userIsInRole(currUser, roles)) {
console.log('User was not in the required roles: %j, %j', currUser.roles, roles);
//throw new Meteor.Error(403, 'Access Denied');
Router.go('notAuthorized');
}
}
} else {
console.log('User not found');
Router.go(AccountUtils.settings.signinRoute);
}
}
}
Now, in my Router router I do something like:
this.route('admin', {
path: '/admin',
onBeforeAction: function() { AccountUtils.authenticationRequired(this, ['ADMIN']); }
});
There are a few moving parts around all of this, but that's the jest of it. In the onBeforeAction of the route, check if the user has the required role. If not, send them to the notAuthorize page. If they are, let them through. I am still missing a few pieces that I haven't worked out yet in this code, but it works for the most part.
Hope that gives you a jumping-off point.
I have a route mixin that will check if the user is authenticated and if not, take them to the login page. Once they login, I redirect them back to the page they initially tried to go to. I'm using Ember's suggested solution for storing and retrying a transition. This works well the way it is. The problem is, when I try to add a query string parameter, it doesn't get passed in the transition.
Now I know I can do this but I'd prefer to use the transition.retry method instead.
Any ideas?
Ember's suggested solution
App.SomeAuthenticatedRoute = Ember.Route.extend({
beforeModel: function(transition) {
if (!this.controllerFor('auth').get('userIsLoggedIn')) {
var loginController = this.controllerFor('login');
loginController.set('previousTransition', transition);
this.transitionTo('login');
}
}
});
App.LoginController = Ember.Controller.extend({
actions: {
login: function() {
// Log the user in, then reattempt previous transition if it exists.
var previousTransition = this.get('previousTransition');
if (previousTransition) {
this.set('previousTransition', null);
previousTransition.retry();
} else {
// Default back to homepage
this.transitionToRoute('index');
}
}
}
});
What I'm currently using
this.transitionTo('posts', {queryParams: {sort: 'title'}});
There is an issue talking about this, and also a related PR been commited. https://github.com/emberjs/ember.js/pull/4008
Currentlly, retry can't pass the query parameters,
I'm having trouble getting Ember to delete a record that has a belongsTo relationship. I have a couple models set up with a one-to-one relationship like this:
App.User = DS.Model.extend({
account: DS.belongsTo('App.Account')
...
});
App.Account = DS.Model.extend({
user: DS.belongsTo('App.User'),
...
});
This is my deleteUser method on my UserController
deleteUser: function() {
user = this.get('model');
var transaction = App.store.transaction();
transaction.add(user);
user.deleteRecord();
transaction.commit();
this.transitionTo('users');
}
When it gets to user.deleteRecord(); I get an error in the console Too much recursion. Trying to step through the problem I found that infinite loop is happening in this section of code in the main ember.js file
var meta = obj[META_KEY], desc = meta && meta.descs[keyName],
isUnknown, currentValue;
if (desc) {
desc.set(obj, keyName, value);
} else {
....
}
deleteRecord calls clearRelationships which calls Ember.set(this, "account", null) on the user object. Inside Ember.set() when it hits the above code it finds the reference to the user object and calls set on it.. which then finds the account and calls set on it.. which finds the user and calls set on it.. etc.
If this is a bug in Ember can anyone help me with a fix or workaround? Here is a jsFiddle of my example
Looks like it was an oversight. This pull request on github fixed the issue for me https://github.com/emberjs/data/pull/715