Display list of user email addresses in Meteor - meteor

I'm trying to get a list of all users in meteor using Metor.methods
This is my code :
server/main.js
Meteor.methods({
'createUser': function(){
if (Meteor.users.find({}).count()===0) {
for (i = 0; i <= 5; i++){
let id = Accounts.createUser({
email: Meteor.settings.ADMIN_USE,
password: Meteor.settings.ADMIN_PASSWORD,
profile: { firstName: Meteor.settings.ADMIN_FIRSTNAME, lastName: Meteor.settings.ADMIN_LASTNAME }
});
}
}
},
'returnmail': function(){
return Meteor.users.findOne().emails[0].address;
}
});
then i call this function in another file called Listusers.js:
Template.ListUsers.helpers({
email: function(){
Meteor.call('returnmail');
},
});
I'm trying to display the value of email using this code but it doesn't work
Client/ListUsers.html
<Template name="ListUsers">
<input id="mail" type="text" value="{{email}}" />
</Template>

Several problems. I strongly recommend you go through the tutorial at least. The Discover Meteor ebook is also invaluable. One of the first steps in understanding Meteor is moving from a traditional XHR request-response model to publish-subscribe.
Your email helper needs to return a value.
Meteor.call() doesn't return anything. Normally you use it with a callback that gives you an error status and the result. However you can't use that in a helper unless you use a Session variable or a promise because the return value from the call is at the wrong context level.
Your returnmail method is only returning a single email address from findOne() and not any specific one either, just a quasi-random one (you can't guarantee which document findOne() is going to return!)
You're creating 5 identical users with the same email address and password. 2-5 are going to fail because of a uniqueness constraint on the email field.
Now on to the solution.
On the server, publish the Users collection including only the emails field (which is an array of objects)
On the client, subscribe to that publication.
On the client, iterate over the users collection and get the email address from a helper.
server:
Meteor.publish('allEmails',function(){
// you should restrict this publication to only be available to admin users
return Meteor.users.find({},{fields: { emails: 1 }});
});
client js:
Meteor.subscribe('allEmails');
Template.ListUsers.helpers({
allUsers(){ return Meteor.users.find({}); },
email(){ return this.emails[0].address; }
});
client html:
<Template name="ListUsers">
{{#each allUsers}}
<input id="mail" type="text" value="{{email}}" />
{{/each}}
</Template>

Related

How do I control two subscriptions to display within a single template?

Sorry kind of new to the Meteor framework!
I Subscribed to two Publish functions. Even if both publish functions target the same Collection, they both have different functions, that I would like to display in one template. How do I achieve this. I have done allot of research but there doesn't seem to be sufficient information on how to achieve.
Following are the two publish functions in code that I subscribe to:
.server/main.js:
Meteor.publish('MerchantTrending', function (categoryMan){
var currentUser = this.userId;
return buyList.find({ who:"Merchant", ownerId:currentUser, itemCategory: { $in: categoryMan } }, {skip: 0, limit: 3});
});
.server/main.js:
Meteor.publish('myTopViews', function (){
var currentUser = this.userId;
return buyList.find({ newArrivalsExpiryDate : {'$lte': new Date()}}, {ownerId:currentUser }, {skip: 0, limit: 3});
});
Following is the subscription function in code
.client/main.js:
Router.route('/MerchantLandingPage', {
subscriptions: function(){
var categoryMan = Session.get('category');
return Meteor.subscribe('MerchantTrending', categoryMan, 'merchantTopViews')
}
});
Now the helper function in code:
Template.MerchantLandingPage.helpers({
'top3Trending' : function () {
return buyList.find({}).fetch();
},
'myTopViews' : function () {
return buyList.find({}).fetch();
}
});
And now the template in code:
<template name="MerchantLandingPage">
##### *** Top three trending items *** ########
{{#each top3Trending}}
ItemName:: <b>{{itemName}}</b> <br>
Item Category:: <b>{{itemCategory}}</b> <br>
Discription:: <b>{{descriptions}}</b> <br>
Image:: {{this.photo._id}} <br>
Date Created:: {{createdDate}} <br>
{{/each}}
<br><br>
############ *** My top Views *** #############
{{#each myTopViews}}
ItemName:: <b>{{itemName}}</b> <br>
Item Category:: <b>{{itemCategory}}</b> <br>
Discription:: <b>{{descriptions}}</b> <br>
Image:: {{this.photo._id}} <br>
Date Created:: {{createdDate}} <br>
{{/each}}
</template>
Both {{#each myTopViews}} and {{#each top3Trending}} successfully display but not correctly. When the variable categoryMan in
Meteor.subscribe('MerchantTrending', categoryMan, 'merchantTopViews')
changes value, it affects both both the outcome of both {{#each myTopViews}} and {{#each top3Trending}}, when its only supposed to affect {{#each top3Trending}}.
How can I get the subscriptions to NOT have an affect on both {{#each myTopViews}} and {{#each top3Trending}}, but only {{#each myTopViews}} in my template?
Thanks for the help!
Welcome to Meteor!
The solution is straight forward once you understand that:
Subscription is just a stream of your DB documents from server into your client's MiniMongoDB. So your 2 subscriptions (it is perfectly fine having several subs on the same Collection) just fill in your client's buyList local collection.
Use of Collections client side is generally independent from how you subscribe the data. So you should simply use a similar selector and possibly options in your top3Trending and myTopViews helpers as you have done for your publication server side (not the same between the 2 helpers, obviously).
As a side note, you do not even need to fetch() the Collection cursor returned by find(), Blaze knows how to handle it directly.
I see a few problems with your code, first of all - your second subscription isn't going to work because your query is wrong:
Meteor.publish('myTopViews', function (){
var currentUser = this.userId;
return buyList.find(
{ ownerId:currentUser, newArrivalsExpiryDate : {'$lte': new Date()}},
{skip: 0, limit: 3}
);
});
You had ownerId: currentUser wrapped in curly braces, it is fixed above.
The way publications/subscriptions work is, if you have two publications sending different data, the template doesn't 'know' the data is coming from two different subscriptions. It will just have access to all of the data being sent by all subscriptions.
For that reason, your two helpers top3trending and myTopViews are returning exactly the same thing. You can delete one of them!
You should move your subscriptions out of the router and in to the Template itself. Here's an article that will help you with that!
There is a package percolate:find-from-publication that permits to filter the data from publications.

Use Flow Router Param in Autoform

Friends,
I'm working on my first app in Meteor and hitting my head against the wall on something...
I have a scenario similar to a blog + comments situation where I have one collection (call it 'posts') and want to associate documents from another collection (call it 'comments').
The best way I know to pass the post._id to the comments as a "postId" field is to use the Flow Router params, since the form is on the 'post/:id' view.
But for the life of me, I cannot figure out how to get "var postId = FlowRouter.getParam('postId');" to pass to Autoform so it populates. I've tried adding it as a function in the schema, as a hook, and as a hidden field in the form on the page (obviously don't want to go that route).
Autoform is amazing and I want to use it, but may have to wire it up the hard way if I can't get this darn value to populate.
Any ideas? I've been hitting my head against the wall on this for a couple of days now.
Thanks!
First, just so we're on the same page, if you have your route is set up like this:
FlowRouter.route('/blog/:postId', {
action: function (params, queryParams) {
FlowLayout.render('layout', { body: 'postTemplate' });
},
});
You are able to call FlowRouter.getParam('postId') from inside the AutoForm hook
You'll need to use an AutoForm hook and have a complete schema. I'm using the package aldeed:collection2 for the schema set up. The postId field must be explicity declared. This code is running on both server and client.
Comments = new Mongo.Collection("comments");
Comments.attachSchema(new SimpleSchema({
comment: {
type: String,
label: "Comment"
},
postId: {
type: String
}
}));
Setting your form up like this is not what you want:
{{> quickForm collection="Comments" id="commentForm" type="insert"}}
That's no good because it will show the postId field in the HTML output. We don't want that, so you have to fully define the form like this:
{{#autoForm collection="Comments" id="commentForm" type="insert"}}
<fieldset>
{{> afQuickField name='comment' rows=6}}
</fieldset>
<button type="submit" class="btn btn-primary">Insert</button>
{{/autoForm}}
Then add the AutoForm hook. This code is running on the client.
var commentHooks = {
before: {
insert: function(doc){
var postId = FlowRouter.getParam('postId');
doc.postId = postId;
return doc;
}
}
};
AutoForm.addHooks(['commentForm'],commentHooks);
Make sure you have your allow/deny rules set up, and it should be working fine.
I was struggling with this same use case as well, and I found this on the Meteor forums: https://forums.meteor.com/t/use-flow-router-param-in-autoform/14433/2
If you're using a schema to build your form (either with the autoform or quickform tags) then you can put it right in there.
For example:
campaignId: {
type: String,
autoform: {
value: function() {
return FlowRouter.getParam('campaignId');
},
type: "hidden"
}
},

How can I create a list of online/active users?

I'm using the package mizzao:user-status to add online/active statuses to my users. Using this, I'm able to run a query to get all online users.
The problem I'm facing is, keeping a list of users up to date with users that are logged in.
I believe I would need to use Accounts.onLogin to update the list, which I think is used on the server side. So, how would I keep a list of users up to date with users that are connected on the client side?
Like mizzao point on the README.
First Do the Publish.
Meteor.publish("userStatus", function() {
return Meteor.users.find({ "status.online": true });
});
and the subscribe,
Meteor.subscribe('userStatus')
Second do a helper to return the users online.
Javascript
Template.example.helpers({
usersOnline:function(){
return Meteor.users.find({ "status.online": true })
},
usersOnlineCount:function(){
//event a count of users online too.
return Meteor.users.find({ "status.online": true }).count();
}
})
HTML
<template name="example">
There are currently {{usersOnlineCount}} users online.
<h1>List of Users online </h1>
<ul>
{{#each usersOnline}}
<li> {{username}}</li>
{{/each}}
</ul>
</template>

Publishing all Meteor.users doesn't work

I'm trying to publish all the usernames to the clients, even if not signed in. For that, on the server I have:
Meteor.publish("users", function() {
return Meteor.users.find({}, {fields : { username : 1 } });
});
And on the client:
Meteor.subscribe("users");
However, when I try to access the Meteor.users collection, I find nothing there.
(This is essentially the same as the question here: Listing of all users in the users collection not working first time with meteor js, only without checking the roles for admin first. Still doesn't seem to work..)
I'm probably missing something silly..
I find the same issue, and after doing a research i find this package, i think it may should help you.
Take a look and hope it help you
Update
First move the subscription to the /lib folder, just to make sure its the first thing meteor do when start, also change a little bit the subscription like this on the /lib, folder.
Tracker.autorun(function() {
if(Meteor.isClient) {
if (!Meteor.user()) {
console.log("sorry you need to be logged in to subscribe this collection")
}else{
Meteor.subscribe('users');
}
}
});
For better security we just subscribe to the users collection when the client its logged in
This code outputs all the usernames to the clients, even if not signed in (in this case on /users page):
server/publications.js:
Meteor.publish("userlist", function () {
return Meteor.users.find({},{fields:{username:1}});
});
client/users_list.js:
Template.usersList.helpers({
users: function () {
return Meteor.users.find();
}
});
client/users_list.html:
<template name="usersList">
{{#each users}}
{{username}}
{{/each}}
</template>
lib/router.js (using iron:router package):
Router.route('/users', {
name: 'usersList',
waitOn: function(){
return Meteor.subscribe("userlist");
}
});
Hope it helps.

Basic pattern: Populate a template with JSON from an external URL in Meteor

I am struggling to figure out the basic pattern for populating a template with data from a call to an external API in Meteor.
These are the elements in play
A fresh Meteor project, created by running meteor create monkeyproject
The URL of an external API that returns a JSON array. Let's say it's example.com/api/getmonkeys. It returns an array of monkeys, each with a different name.
A Handlebar template called monkeyTemplate with an {{#each}} loop. Let's say it's this:
<template name="monkeyTemplate">
{{# each monkeys}}
One of our monkeys is named {{name}}. <br>
{{/each}}
<input type="button" id="reload" value="Reload monkeys" />
</template>
What I want to happen
When the page loads fill monkeyTemplate with monkeys from our external URL.
When the user clicks the button, call the external URL again to reload the monkeys.
The question
What is a standard pattern for doing the above in Meteor? At the risk of cluttering up the question, I'll include some starting points, as I understand them.
We can populate the template with whatever we return from our Template.monkeyTemplate.monkeys function. How do we fill it with content from an external URL, given that the page will load before the external request is finished?
We can get our JSON by using Meteor.HTTP.call("GET", "http://example.com/api/getmonkeys", callback ). Where do we put this request, and what do we put into our callback function in this situation?
We can control what happens on the server side and what happens on the client side by using the Meteor.isServer/Meteor.isClient conditions, or by putting our code into files called client and server folders. What code needs to be on the server side vs. the client side?
We determine what happens when the button is clicked by attaching a function to Template.monkeyTemplate.events['click #reload']. What goes into our callback function in this situation?
I will refrain from cluttering up the question with my crappy code. I am not looking for anyone to write or rewrite an application for me—I am just looking for the guidelines, standard patterns, best practices, and gotchas. Hopefully this will be instructive to other beginners as well.
I'm not sure if this is the "standard" template, but it serves the purpose pretty well.
Set up two data helpers for the template, monkeys and loading. First one will display the actual data once it's fetched, the latter will be responsible for notifying user that the data is not yet fetched.
Set up a dependency for these helpers.
In created function of the template, set loading helper to true and fetch the data with HTTP call.
In the callback, set the template data and fire the dependency.
html
<template name="monkeys">
{{#if loading}}
<div>Loading...</div>
{{/if}}
{{#if error}}
<div>Error!</div>
{{/if}}
{{#each monkeys}}
<div>{{name}}</div>
{{/each}}
<div><button class="monkeys-reloadMonkeys">Reload</button></div>
</template>
js
var array = null;
var dep = new Deps.Dependency();
Template.monkeys.created = function() {
reloadMonkeys();
};
Template.monkeys.events({
'click .monkeys-reloadButton': function(e,t) {
reloadMonkeys();
};
});
var reloadMonkeys = function() {
array = null;
dep.changed();
HTTP.get('http://example.com/api/getmonkeys', function(error, result) {
if(!error && result) {
array = result;
} else {
array = 0;
}
dep.changed();
});
};
Template.monkeys.monkeys = function() {
dep.depend();
return array ? array : [];
};
Template.monkeys.loading = function() {
dep.depend();
return array === null;
};
Template.monkeys.error = function() {
dep.depend();
return array === 0;
};

Resources