Template helper to wait till user account gets checked - meteor

This Meteor client code causes the headerLabel on the page to flicker first to "Please login" then to "Select item from menu" in the case of an existing valid account. How can it be fixed so that it shows no "Please login" since their is a user logged in already? Thanks
edit
As suggested in Ramil's answer. the modified code below still does not work and I still get the flicker of "Please login".
Template.header.helpers({
headerLabel: () => {
const user = Meteor.user();
if (user) {
return user.profile.header || Session.get('header') || 'Select item from menu';
} else {
return 'Please login';
}
}
});
<template name="header">
<header>
<h1 class="main-menu">
<button class="mainMenu" type="button">☰</button>
</h1>
{{#if currentUser}}
<p class="header">
{{headerLabel}}
</p>
{{else}}
<p class="header">
Please login
</p>
{{/if}}
<h1>
<button class="subMenu" type="button">⋮</button>
</h1>
</header>
</template>

There is builtin {{currentUser}} helper in accounts package.
You can use it to check whether the user is logged in.
<template name="header">
<header>
{{#if currentUser}}
<p>
Select item from menu
</p>
{{else}}
<p>
Please login
</p>
{{/if}}
</header>
</template>

Related

grab the value of an element in a different template

The code below is trying to grab the username and password from input elements on a template.login and createUser when a button which is in template.footer is clicked.
Being new to javascript and Meteor, my code below probably butchered both.
I thought to make a method call from the footer click event, this call gets the username and password and fires Meteor accounts create and store the returned userId in a local session to be used later. blah..blah..
But how can I get access to input values in one template from another?
so I need your help. Thanks
Template.footer.events({
'click .myClass': function (event, template) {
Meteor.call('loginUser', username,password);
}
});
Meteor.methods({
//store the useId returned from createUser in a local session userId
loginUser: function (username, password) {
Accounts.createUser(username, password, function () {
Session.set(userId, this.value);
});
}
});
<template name="footer">
<footer>
<nav class="navbar navbar-default navbar-fixed-bottom">
<div class="container">
<div class="row">
{{#each footerButtons}}
<h2>
<button class="col-xs-{{footerButtonsScaling}} myClass" type="button">{{text.toUpperCase}}</button>
</h2>
{{/each}}
</div>
</div>
</nav>
</footer>
</template>
<template name="login">
<form action="">
<input type="text" name="username" placeholder="type your ID" value="{{username}}">
<input type="password" name="password" placeholder="type your PIN" value="{{password}}">
</form>
</template>
You can just use jQuery to access field values anywhere in the DOM:
var username = $('[name="username"]').val();
var password = $('[name="password"]').val();

meteor database insert in global collection

The code below should insert the selected item value in the Tasks collection, retain the info for later use, and a headerLabel should show the task selected. I am not able to get the headerLabel to show the task when the click .menuItem function runs. Thanks
Tasks = new Mongo.Collection('tasks');
Template.mainMenu.events({
'click .menuItem': function(event){
Tasks.insert({menuItem: $(event.currentTarget).data('value')});
}
});
Template.header.helpers({
headerLabel: function( id ){
return Tasks.findOne({_id: id}).menuItem;
},
tasks: function(){
return Tasks.find();
}
});
<template name="mainMenu">
<div class="container">
<div class="row">
<section class="col-xs-12">
<div class="list-group">
{{#each menuItems}}
<a href="#" class="list-group-item menuItem" data-value={{menuItem}}>
<img src="/abc.png">
{{menuItem}} <span class="badge">></span>
</a>
{{/each}}
</div>
</section>
</div>
<template name="header">
<h1><button class="col-xs-2 mainMenu" type="button">☰</button></h1>
<h3>
<label class="col-xs-8 text-center">
{{#if headerLabel}} {{headerLabel}} {{else}} Select an item {{/if}}
</label>
</h3>
<h1><button class="col-xs-2" type="button">⋮</button></h1>
</template>
Assuming that the click can happen multiple times, you'll need to pass an _id for the appropriate task into your helper:
Tasks = new Mongo.Collection('tasks');
Template.mainMenu.events({
'click .menuItem': function(event){
Tasks.insert({menuItem: $(event.currentTarget).data('value')});
}
});
Template.header.helpers({
headerLabel: function( id ){
var task = Tasks.findOne({_id: id});
if( task ) {
return task.menuItem;
}
},
tasks: function() {
return Tasks.find();
}
});
So what I'm doing there is saying find one task's menuItem that has the ID passed to the helper. I also added a tasks helper to get all tasks. So your template might look something like:
<template name="mainMenu">
{{#each task in tasks}}
<h4>{{headerLabel task._id}}</h4>
<!-- Additional code here... -->
{{/each}}
</template>
You'll obviously need to customize the HTML to your specific situation, but that should give you the gist. Hope that helps!

How can I route my messenger and messages in Meteor?

Im creating a an instant messenger app and im having a little trouble routing it. So, once you go into the app. There is a list of available users. You can click on a user and start chatting. The issue I have is once I click send, the console show an Uncaught TypeError: Cannot read property 'value' of undefined. Im not sure what im doing wrong here. Also I need help show the chat messages sent above. As if you can see the recent and previous messages. Here are my codes. Any examples and helps would be great.
HTML
minstant
<body>
</body>
<!-- this is the main template used by iron:router to build the page -->
<template name="ApplicationLayout">
{{> yield "header"}}
<div class="container">
{{> yield "main"}}
</div>
</template>
<!-- top level template for the nav bar -->
<template name="navbar">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">
Minstant!
</a>
</div>
<div class="nav navbar-nav">
{{> loginButtons}}
</div>
</div>
</nav>
</template>
<!-- Top level template for the lobby page -->
<template name="lobby_page">
{{> available_user_list}}
</template>
<!-- display a list of users -->
<template name="available_user_list">
<h2>Choose someone to chat with:</h2>
<div class="row">
{{#each users}}
{{> available_user}}
{{/each}}
</div>
</template>
<!-- display an individual user -->
<template name="available_user">
<div class="col-md-2">
<div class="user_avatar">
{{#if isMyUser _id}}
<div class="user_avatar">{{getUsername _id}} (YOU)
<br/>
<img src="/{{profile.avatar}}" class="avatar_img">
</div>
{{else}}
<a href="/chat/{{_id}}">
{{getUsername _id}}
<br/>
<img src="/{{profile.avatar}}" class="avatar_img">
</a>
{{/if}}
</div>
</div>
</template>
<!-- Top level template for the chat page -->
<template name="chat_page">
<h2>Type in the box below to send a message!</h2>
<div class="row">
<div class="col-md-12">
<div class="well well-lg">
{{#each recentMessages}}
{{> message}}
{{/each}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form class="new-message">
<input class="input" type="text" name="chat" placeholder="type a message here...">
<button class="btn btn-default">Send</button>
</form>
</div>
</div>
</template>
<!-- simple template that displays a message -->
<template name="message">
<div class = "container">
<div class = "row">
<div class = "username">{{username}}
<img src="/{{profile.avatar}}" class="avatar_img">
</div>
<div class = "message-text"> said: {{messageText}}</div>
</div>
</div>
</template>
Here is my JS
Messages = new Mongo.Collection("messages");
if (Meteor.isClient) {
Meteor.subscribe("messages");
Meteor.subscribe("userStatus");
// set up the main template the the router will use to build pages
Router.configure({
layoutTemplate: 'ApplicationLayout'
});
// specify the top level route, the page users see when they arrive at the site
Router.route('/', function () {
console.log("rendering root /");
this.render("navbar", {to:"header"});
this.render("lobby_page", {to:"main"});
});
// specify a route that allows the current user to chat to another users
Router.route('/chat/:_id', function () {
this.render("navbar", {to:"header"});
this.render("chat_page", {to:"main"});
});
///
// helper functions
///
Template.available_user_list.helpers({
users:function(){
return Meteor.users.find();
}
})
Template.available_user.helpers({
getUsername:function(userId){
user = Meteor.users.findOne({_id:userId});
return user.profile.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
Template.chat_page.helpers({
recentMessages: function () {
return Messages.find({}, {sort: {createdAt: 1}});
return Meteor.users.find();
},
});
Template.chat_page.events({
// this event fires when the user sends a message on the chat page
'submit .new-message':function(event){
event.preventDefault();
var text= event.target.text.value;
// stop the form from triggering a page reload
event.target.text.value = "";
// see if we can find a chat object in the database
// to which we'll add the message
Meteor.call("SendMessage", text);
},
});
};
Meteor.methods({
sendMessage: function (messageText) {
if (! Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
Messages.insert({
messageText: messageText,
createdAt: new Date(),
username: Meteor.user().username
});
}
});
// start up script that creates some users for testing
// users have the username 'user1#test.com' .. 'user8#test.com'
// and the password test123
if (Meteor.isServer) {
Meteor.startup(function () {
if (!Meteor.users.findOne()){
for (var i=1;i<9;i++){
var email = "user"+i+"#test.com";
var username = "user"+i;
var avatar = "ava"+i+".png"
console.log("creating a user with password 'test123' and username/ email: "+email);
Meteor.users.insert({profile:{username:username, avatar:avatar}, emails: [{address:email}],services:{ password:{"bcrypt" : "$2a$10$I3erQ084OiyILTv8ybtQ4ON6wusgPbMZ6.P33zzSDei.BbDL.Q4EO"}}});
}
}
},
),
Meteor.publish("messages", function () {
return Messages.find();
});
Meteor.publish("userStatus", function() {
return Meteor.users.find({ "status.online": true });
});
};
The error is with your form submit code. In the console you can see the error is in Template.chat_page.events.submit .new-message on line 73. That will take you right to the error code:
'submit .new-message':function(event){
event.preventDefault();
var text = event.target.text.value;
// stop the form from triggering a page reload
event.target.text.value = "";
}
event.target.text.value doesn't exist. event.target does, but there is no field for text. There is textContent, and you can access the children of the target (which in this case is the form). Put in a console.log(event); and figure out what you are trying to access within the javascript console and then use that to determine what your code should look like. This might work for you:
'submit .new-message':function(event){
event.preventDefault();
var text = event.target.elements.chat.value;
// stop the form from triggering a page reload
event.target.text.value = "";
}
event.target.elements.chat.value comes from the name field of the <input>.

How to reload (re render) template in Meteor

I am working on a chat app that supports multiple languages. The basics of the app is working fine however I have small problem when changing chat rooms.
Each room is setup to support 2 languages. When sending a chat message you can choose which language you are sending the message in. This is done by clicking on a small icon of a flag which toggles between the 2 flag icons. The template for this is:
<template name="chatBar">
<div id="chatBar" class="input-append input-prepend">
<form id="chatForm">
<span class="add-on"><img src="/images/flags-iso/flat/16/{{chatMessageLang}}.png" id="lang"></span>
<input id="chatMessageLanguage" type="hidden" value="{{chatMessageLang}}">
<input id="chatMessageTarget" type="hidden" value="{{chatMessageTargetLang}}">
<input class="input-xxlarge" id="chatMessage" type="text" placeholder="← choose your language and then type your message here…">
<button class="btn" id="sendNewMessage" type="submit">Send</button>
</form>
</div>
and is called from another template:
<template name="chat">
{{> chatroom}}
<div id="chatWindow">
<ul>
{{#each chats}}
<li class="{{messageClass}} {{_id}}">
<img src="/images/flags-iso/flat/16/{{langOriginal}}.png">
{{langTo.flagicon}}
{{user}}:
<span class="message" lang="{{langOriginal}}">{{original}}</span>
{{#if translated}}
<span class="message" lang="{{langTranslated}}">{{translated}}</span>
{{/if}}
{{#if correction}}
<i class="icon-remove"></i>
<span class="friendCorrection">{{correction}}</span>
{{/if}}
<span class="messageOptions">{{{messageOptions}}}</span>
</li>
{{/each}}
</ul>
</div>
{{> chatBar}}
</template>
The problem I have is when I change chatrooms the language options are being retained from the previous chatroom I was in. The code for setting the languages for the chatbar is:
Template.chatBar.helpers({
chatMessageLang: function() {
//return getCurrentChatroomInfo().langFrom.iso;
return Meteor.user().profile.langNative;
},
chatMessageTargetLang: function() {
var chatroomLang1 = getCurrentChatroomInfo().langFrom.iso;
var chatroomLang2 = getCurrentChatroomInfo().langTo.iso;
if(Meteor.user().profile.langNative == chatroomLang1){
return chatroomLang2;
} else {
return chatroomLang1;
}
}});
function getCurrentChatroomInfo(){
return Chatrooms.findOne({_id : Router.current().params['_id']})
}
How do I make the variable chatMessageTargetLang reactive to the loaded chatroom (each chatroom has their own route).
Thanks
Adam

Adding an user field to a Meteor record?

Right now, my Posts model has a title and a content field:
client/client.js:
Meteor.subscribe('all-posts');
Template.posts.posts = function () {
return Posts.find({});
};
Template.posts.events({
'click input[type="button"]' : function () {
var title = document.getElementById('title');
var content = document.getElementById('content');
if (title.value === '') {
alert("Title can't be blank");
} else if (title.value.length < 5 ) {
alert("Title is too short!");
} else {
Posts.insert({
title: title.value,
content: content.value,
author: userId #this show displays the id of the current user
});
title.value = '';
content.value = '';
}
}
});
app.html:
<!--headder and body-->
<div class="span4">
{{#if currentUser}}
<h1>Posts</h1>
<label for="title">Title</label>
<input id="title" type="text" />
<label for="content">Content</label>
<textarea id="content" name="" rows="10" cols="30"></textarea>
<div class="form-actions">
<input type="button" value="Click" class="btn" />
</div>
{{/if}}
</div>
<div class="span6">
{{#each posts}}
<h3>{{title}}</h3>
<p>{{content}}</p>
<p>{{author}}</p>
{{/each}}
</div>
</div>
</div>
</template>
I tried adding an author field (already did meteor add accounts-password and accounts-login):
author: userId
But it just shows the id of the current user who is logged in.
I would like it to show the email of the author of the post instead.
How to accomplish that?
I think you can get the email with
Meteor.users.findOne(userId).emails[0];
#danielsvane is correct, but since your Post document's author field stores the _id of the author and not the email address, you'll need a template helper in order for the template to know how to get the email address. Try the following:
// html
...
<div class='span6'>
{{#each posts}}
{{> postDetail}}
{{/each}}
</div>
...
<template name="postDetail">
<h3>{{title}}</h3>
<p>{{content}}</p>
<p>{{authorEmail}}</p>
</template>
// javascript
Template.postDetail.helpers({
// assuming the `author` field is the one storing the userId of the author
authorEmail: function() { return Meteor.users.findOne(this.author).emails[0]; }
});
If it's always showing the current user and not the user who is the author of the post, then the problem lies in how you're setting the value of the userId variable in your event handler, which isn't code that you showed in your question.

Resources