this.userId not displaying user - meteor

I'm publishing users and a second collection called joboffers. The joboffers collection stores the userIds for employer and candidate. I would like to get the candidate name to display next to the joboffer, for an admin page, however nothing I do seems to work. All of the joboffers display but not the candidate name. In my console I just get object .
Path: publish.js
// publish all jobs for admin to view
Meteor.publish('allJobs', function () {
return JobOffers.find({});
});
Meteor.publish('allUsersWithJobs', function () {
var offers = JobOffers.find({}, {fields: {candidateUserId: 1}}).fetch();
var ids = _.pluck(offers, 'candidateUserId');
options = { fields: {username: 1, emails: 1, "profile.firstName": 1, "profile.familyName": 1 } };
return Meteor.users.find({ _id: { $in: ids } }, options);
});
Path: alljoboffers.js
Template.alljoboffers.onCreated(function() {
Meteor.subscribe("allJobs");
Meteor.subscribe("allUsersWithJobs");
});
Template.alljoboffers.helpers({
alljoboffers: function() {
return JobOffers.find({});
},
candidateName: function() {
console.log(this);
var user = this.userId;
var candidate = (user && user.profile && user.profile.firstName);
return candidate;
},
});
Path: alljoboffers.html
{{#each alljoboffers}}
{{positionTitle}}
{{#with candidateName}}
{{profile.firstName}}
{{/with}}
{{/each}}

You're mixing user id and user object. It's a good idea to create a global helper to help keep a convention on how you manage them. This will help reduce the confusion. For example:
Template.registerHelper('usernameById', function(userId) {
var user = Meteor.users.findOne({_id: userId});
return user && user.profile.firstName;
});
Then in your template:
{{#each alljoboffers}}
{{positionTitle}}
{{usernameById candidateUserId}}
{{/each}}

Related

Display content based on roles

When an is_admin user looks at the profile of another user I want to be able to control the type of information that is displayed based on the users profile roles. My code below displays nothing, what am I doing wrong?
Path: adminView.js
Template.adminView.helpers({
profile: ()=> {
var id = FlowRouter.getParam('id');
return Meteor.users.findOne({_id: id});
},
userRole: function () {
var roles = this.roles;
if (roles === "is_student") {
return true;
}
}
});
Path: adminView.html
{{#with profile}}
{{#if userRole}}
display user
{{/if}}
{{/with}}
Since roles is an array you have to check for existence of the value in the array, not equality:
userRole: function () {
var roles = this.roles;
return (roles.indexOf("is_student") > -1 );
}

Meteor publish - subscribe user profile

I'm trying to publish a user profile. I have the following publish function in publish.js:
Meteor.publish("singleProfile", function ( profileId ) {
check(profileId, String);
return Meteor.users.find(profileId, { fields: { _id: 1, services: 1, profile: 1 }});
});
This is my route in router.js:
Router.route('/profile/:_id', {
name: 'profilePage',
template: 'appProfile',
onBeforeAction: function() {
var currentUser = Meteor.userId();
if(currentUser) {
this.next();
} else {
this.render("signin");
}
},
waitOn: function() {
this.response = Meteor.subscribe('singleProfile', this.params._id);
return this.response;
},
action: function() {
this.render('appProfile');
}
});
Question is, how do I access the profile details in the appProfile template? Do I need a template helper defined? Or do I need to modify this code?
You can use a template helper for this:
Template.appProfile.helpers({
users() {
return Meteor.users.find();
}
});
Then in your template:
...
{{#each users}}
{{profile.myProperty}} <!-- Renders the myProperty field of the profile. -->
{{/each}}

Adding collection items as routes in Meteor

I have a meteor project where all my users have their own profile page setup in this way using routes:
Routes code:
Router.route('/#:username', {
name: 'profile',
controller: 'ProfileController'
});
ProfileController = RouteController.extend({
template: 'profile',
waitOn: function() {
return Meteor.subscribe('userProfile', this.params.username);
},
data: function() {
var username = Router.current().params.username;
return Meteor.users.findOne({
username: username
});
}
});
Server code:
Meteor.publish('users', function() {
return Meteor.users.find({}, {fields: {username: 1, emails: 1, profile: 1, roles: 1}});
});
Meteor.publish('userProfile', function(username) {
// Try to find the user by username
var user = Meteor.users.findOne({
username: username
});
// If we can't find it, mark the subscription as ready and quit
if (!user) {
this.ready();
return;
}
// If the user we want to display the profile is the currently logged in user
if(this.userId === user._id) {
// Then we return the curresonding full document via a cursor
return Meteor.users.find(this.userId);
} else {
return Meteor.users.find(user._id, {
fields: {
profile: 0
}
});
}
});
I want to do something similar with a pages collection that I've set up. Creating the collection works and the collection page has an _id field that is made upon creation.
Right now the program works nicely for users where mysite.com/# works. Now I want the same thing to work for mysite.com/&
I've basically attempted to do the exact same thing as I did in the above code with the user name but it wasn't working. I've checked to make sure my creation of the collection items are working and they are. But somehow I can't figure out how to do this same thing with collections since I'm relatively new to using routes.
This is what I've attempted:
Here's my routes:
var pageRoute = '/&:_id';
Router.route(pageRoute, {
name: 'page',
controller: 'PageController'
});
PageController = RouteController.extend({
template: 'page',
waitOn: function() {
return Meteor.subscribe('Page', this.params._id);
},
data: function() {
var _id = Router.current().params._id;
return Meteor.pages.findOne({
_id: _id
});
}
});
Server code:
Meteor.publish('pages', function() {
return Pages.find({});
});
Meteor.publish('Page', function(_id) {
// Try find the page by _id
var page = Meteor.pages.findOne({
_id: _id
});
// If we can't find it, mark the subscription as ready and quit
if (!page) {
this.ready();
return;
}
// If the page we want to display is not claimed, display it
if(true) {
return Meteor.pages.find(this._id);
} else {
// Redirect to the page
}
});
The Schema of the Page Collection:
_id: ,
createdAt: ,
CreatedBy: ,
claimedAt: ,
claimedBy: ,
Update:
I've scoped it down to this problem, I get the following error in the console server-side:
I20160202-11:16:24.644(2)? Exception from sub qrPage id 2kY6RKCTuCpBDbuzm TypeError: Cannot call method 'findOne' of undefined
I20160202-11:16:24.645(2)? at [object Object].process.env.MAIL_URL [as _handler] (server/ecclesia.life_server.js:40:33)
I20160202-11:16:24.645(2)? at maybeAuditArgumentChecks (livedata_server.js:1698:12)
I20160202-11:16:24.645(2)? at [object Object]._.extend._runHandler (livedata_server.js:1023:17)
I20160202-11:16:24.645(2)? at [object Object]._.extend._startSubscription (livedata_server.js:842:9)
I20160202-11:16:24.646(2)? at [object Object]._.extend.protocol_handlers.sub (livedata_server.js:614:12)
I20160202-11:16:24.646(2)? at livedata_server.js:548:43
This error occurs whenever I try to direct to mysite.com/&<_id>
Based on this website: https://perishablepress.com/stop-using-unsafe-characters-in-urls/
It looks like # is considered an unsafe character to use in a URL string. On the web page above, it looks like there are several symbols you could use instead as safe characters.
I just tried this on my own machine, and I don't think Meteor plays nicely when the # is introduced in the URL.
This got it working...
Publications:
Meteor.publish('qrpages', function() {
return QRPages.find({});
});
Meteor.publish('qrPage', function(id) {
// Try find the qrpage by _id
var qrpage = QRPages.find({_id: id});
// If we can't find it, mark the subscription as ready and quit
if (!qrpage) {
this.ready();
return;
}
return qrpage;
});
Routes:
var qrpageRoute = '/$:_id';
Router.route(qrpageRoute, {
name: 'qrpage',
controller: 'QRController'
});
QRController = RouteController.extend({
template: 'qrpage',
waitOn: function() {
var id = this.params._id;
return Meteor.subscribe('qrPage', id);
},
data: function() {
var id = this.params._id;
return QRPages.findOne({
_id: id
});
}
});

How to created a load feature during account creation with Meteor

I have a Meteor project where there's generally a delay during the sign up process for new users due to slow connection etc. Is there a way to create a loading screen during this procedure?
I do currently have the sacha:spin package which I use with the iron:router package when different pages are retrieving data to yield. Eg. for my home page I display all the users (mainly for debugging purposes) using this code in my routes:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading'
});
Router.route('/', {
name: 'home',
controller: 'HomeController'
});
HomeController = RouteController.extend({
template: 'home',
waitOn: function() {
return Meteor.subscribe('users');
}
});
Here's my spinner template (nice and simple):
<template name="loading">
{{> spinner}}
</template>
This setup works so nicely, so I was wondering if it would be easy to implement on my create account procedure that I have here:
Template.signup.events({
'submit #signup-form': function(event, template) {
event.preventDefault();
var validated = true,
username = ...,
email = ...,
firstName = ...,
lastName = ...,
password = ...,
// Validation
if (validated) {
Accounts.createUser({
username: username,
email: email,
password: password,
profile: {
firstName: firstName,
lastName: lastName
}
},
function(err) {
if (err) {
// Handle it
} else {
Router.go('home');
}
});
return false;
}
});
Can I use my loader that I used for my home template with the create account procedure?
I would use reactive-var to handle this.
https://atmospherejs.com/meteor/reactive-var
Then, in your template code:
Template.signup.onCreated( function() {
Template.instance().isLoading = new ReactiveVar(false);
});
Template.signup.helpers({
isLoading() {
return Template.instance().isLoading.get();
}
});
Template.signup.events({
'submit #signup-form': function(event, template) {
event.preventDefault();
var validated = true,
username = ...,
email = ...,
firstName = ...,
lastName = ...,
password = ...,
// Validation
if (validated) {
template.isLoading.set(true);
Accounts.createUser({
username: username,
email: email,
password: password,
profile: {
firstName: firstName,
lastName: lastName
}
},
function(err) {
if (err) {
// Handle it
} else {
Router.go('home');
}
template.isLoading.set(false);
});
return false;
}
});
And in the current signup template you'll need to have the structure:
{{#unless isLoading}}
<!-- YOUR CONTENT GOES HERE -->
{{else}}
{{> loading}}
{{/unless}}

How to handle this kind of not found error in iron-router?

For example, I have a Posts collection, which has userId indicates this post belongs to whom.
And I have a route like this:
Router.route('/:username/posts', {
waitOn: function(){
return Meteor.subscribe('posts', username); // A
// var user = Meteor.users.find({username: username}); //B
// if(user) {
// return Meteor.subscribe('posts', user._id);
// } else {
// return null; // ???
// }
}
});
And publish
Meteor.publish("posts", function(userId){ // C
check(userId, String);
return Posts.find({userId: userId});
});
Meteor.publish("posts", function(username){ // D
check(username, String);
if(user) {
return Posts.find({userId: user._id});
} else {
return null; // ???
}
});
I'm confused how to handle like GET /notexistusername/posts ??
You can configure a notFoundTemplate for iron-router either globally or on a per-route basis.
Globally:
Router.configure({
layoutTemplate: 'layout',
notFoundTemplate: 'notFound',
loadingTemplate: 'loading'
});
In a specific route (also I've cleaned up your route code):
Router.route('/:username/posts', {
notFoundTemplate: 'notFound',
data: function(){
var userId = Meteor.users.find({ username: this.params.username })._id;
return Posts.find({ userId: userId });
},
waitOn: function(){
var userId = Meteor.users.find({ username: this.params.username })._id;
return Meteor.subscribe('posts', userId);
}
});
Your notFound template would typically be your 404 page.
Also you can simplify your publication to:
Meteor.publish("posts", function(username){
check(username, String);
return Posts.find({username: username});
});
Since if there are no matches the find will return a null cursor and that will tell the route there's no data.

Resources