When I hit the /login route as triggered below, the correct route renders, but the top of the page begins with my template, not my layoutTemplate. I have to scroll up in order to see the layoutTemplate configured in the route.
if(! Meteor.userId()){
Session.set('single_post_not_logged_in', Session.get('post_id'));
Router.go('/login');
}
This is the route that gets triggerd:
Router.route('login', {
path: '/login',
layoutTemplate: 'loginLayoutTemplate',
template: 'login_template',
onBeforeAction: function(){
if(Meteor.loggingIn()){
var post_visited = Session.get('single_post_not_logged_in');
console.log(post_visited);
if(post_visited != undefined){
Router.go('/post/' + post_visited);
}
}
this.next();
}
});
And finally, here is the layout template that the route is leaving (layoutTemplate) and the new layout template (loginLayoutTemplate)
<body>
{{renderPage}}
</body>
<template name = 'layoutTemplate'>
{{> loginButtons}}
<a id = 'home_button' href="{{pathFor 'home'}}"><h1 id='layout_header'>snippetExchange</h1></a>
<div id='layout_header_row_2'>
<h2 id='layout_by_line'>valuable answers</h2>
<a id = 'new_post_button' href="{{pathFor 'new_post'}}">new post</a>
</div>
{{> yield}}
</template>
<template name = 'loginLayoutTemplate'>
<a id = 'home_button' href="{{pathFor 'home'}}"><h1 id='layout_header'>snippetExchange</h1></a>
<div id=''>
<h2 id='layout_by_line'>valuable answers</h2>
</div>
{{> yield}}
</template>
<template name = 'login_template'>
<h3>please login or create an account</h3>
{{> loginButtons}}
</template>
Try:
Template.login_template.onRendered(function(){
window.scrollTo(0, 0);
});
Related
I've written code for a website which allows you to login and chat with other users. The root page has a list of the users you can chat to. Here's the code:
<!-- 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 class="cha_heading">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="bg-success">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}} (YOU)</div>
</div>
{{else}}
<a href="/chat/{{_id}}">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}}</div>
</a>
{{/if}}
</div>
</div>
</template>
and the 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.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
I've written publish/subscribe code for Chats collection but that's for when you click on one of the users and sends them a message. Now that I've removed autopublish, in the root page, the user can't see any other users to click on. Can someone please help with this issue?
Meteor.users will only publish the current users profile if autopublish is removed.
Add the below publish to your server code:
Meteor.publish(null, function () {
if (!this.userId) return this.ready();
return Meteor.users.find({});
});
A null publish will be auto-published and auto-subscribed by the client if autopublish is removed.
Also, remember to include only those fields that are not sensitive. For, Eg. you might want to omit the password field or the services field.
Something like this:
Meteor.users.find({}, {
fields: {
profile : 1,
emails : 1
}
});
Here's the relevant code template code:
<!-- display a list of users -->
<template name="available_user_list">
<h2 class="cha_heading">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="bg-success">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}} (YOU)</div>
</div>
{{else}}
<a href="/chat/{{_id}}">
{{> avatar user=this shape="circle"}}
<div class="user_name">{{getUsername _id}}</div>
</a>
{{/if}}
</div>
</div>
</template>
<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 messages}}
{{> chat_message}}
{{/each}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form class="js-send-chat">
<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="chat_message">
<div class="chat-message">
{{> avatar user=user size="small" shape="circle"}} <div class="chat-center">{{user}}: {{text}}</div>
</div>
</template>
and the template helpers:
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.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
Template.chat_page.helpers({
messages:function(){
var chat = Chats.findOne({_id:Session.get("chatId")});
return chat.messages;
},
other_user:function(){
return ""
},
})
Template.chat_message.helpers({
user: Meteor.user()
})
I'm making an website where users can log in and chat with each other. I've downloaded the utilities:avatar package to show the avatars of the users. The avatar image is based on the first initial of the username of the user. When I render the avatar template in the template available_user with the code {{> avatar user=this shape="circle"}}, it shows the initials in the avatars fine because it's with the context of the users collection.
I also want to show the avatar when a user sends a message but the template chat_message is within the data context of an array inside the chats collection. So it only shows the default avatar without the initial.
the documentation for the package doesn't quite specify how I can set the template parameter for user or userId. Can someone please help with this issue?
I figured it out. I included the user id into each object in the messages array under the field userId and in the template I set it as {{> avatar userId=userId size="small" shape="circle"}}
I'm using Intellij and Meteor to make an application and I'm trying to use Iron Router to create multiple pages, but when I call the Router in the Javascript file, it says that Router is an unresolved variable and that route is an unresolved function or method. I've checked the meteor folder and it appears that all the Iron Router files loaded fine. At the bottom of the root page I am working on it says
Oops, looks like there's no route on the client or the server for url:
"http://localhost:3000/."
If I navigate to http://localhost:3000/about, which is the only page I have a route set up for yet, the page is blank, except for my nav bar.
Here is my javascript file...
Items = new Mongo.Collection("items");
Found_items = new Mongo.Collection("found_items");
Router.route('home', {path: '/'}); // Add this route
Router.route('about', {path: '/about'});
if (Meteor.isClient) {
// This code only runs on the client
Template.body.helpers({
items: function () {
return Items.find({});
},
found_items: function () {
return Found_items.find({});
},
priceSum: function(){
var userItems = Found_items.find({
userId: this._id
}).fetch();
var prices = _.pluck(userItems, "price");
var totalTaxed = _.reduce(prices, function(sum, price){
var total = sum + parseFloat(price);
return total + (total * 0.04712);
}, 0);
return totalTaxed.toFixed(2);
},
calcTax: function () {
var userItems = Found_items.find({
userId: this._id
}).fetch();
var prices = _.pluck(userItems, "price");
var tax = _.reduce(prices, function(sum, price){
return (sum + parseFloat(price)) * 0.04712;
}, 0);
return tax.toFixed(2);
}
});
Template.body.events({
"submit .new-item": function (event) {
event.preventDefault();
var text = event.target.text.value;
Items.insert({
text: text,
createdAt: new Date(),
owner: Meteor.userId(),
username: Meteor.user().username
});
event.target.text.value = "";
}
});
Template.item.events({
"click .found": function (event, template) {
event.preventDefault();
var price = template.find('[name="price"]').value;
var text = template.find('.text').textContent;
Items.remove(this._id);
Found_items.insert({
text: text,
price: price
});
}
});
Template.body.events({
"click .remove": function(event) {
event.preventDefault();
Found_items.remove(this._id);
}
});
Accounts.ui.config({
passwordSignupFields: "USERNAME_ONLY"
});
}
And here is the HTML file
<head>
<title>Grocery List</title>
</head>
<template name="home">
<body>
<div>
<ul class="menu">
<li class="menuItem">{{> loginButtons}}</li>
<li class="menuItem">Home </li>
<li class="menuItem">About</li>
</ul>
</div>
{{#if currentUser}}
<div class="container">
<header>
<h1 id="title">Grocery List</h1>
<form class="new-item">
<input type="text" name="text" placeholder="Type to add new items" />
</form>
</header>
<ul>
{{#each items}}
{{> item}}
{{/each}}
</ul>
</div>
<div class="container">
<header>
<h1>Items Found</h1>
</header>
<ul>
{{#each found_items}}
{{> found}}
{{/each}}
</ul>
</div>
<div class="container">
<header>
<h3>
Tax: ${{calcTax}}
</h3>
<h2>
Total: ${{priceSum}}
</h2>
<button class="save">Save list</button>
</header>
</div>
{{else}}
<h3>Please log in first.</h3>
{{/if}}
</body>
</template>
<template name="item">
<li>
<button class="found">Got it!</button>
<input type="number" name="price" placeholder="Sale Price" />
<span class="text">{{text}}</span>
</li>
</template>
<template name="found">
<li>
<button class="remove">×</button>
<span class="text">{{text}}</span>
<span class="price">{{price}}</span>
</li>
</template>
<template name="about">
<head>
<title>About Grocery List</title>
</head>
<body>
<div>
<ul class="menu">
<li class="menuItem">{{> loginButtons}}</li>
<li class="menuItem">Home </li>
<li class="menuItem">About</li>
</ul>
</div>
<div class="container">
<header><h1>About</h1></header>
<p>This application was created using Meteor. It can be used to make, save and update grocery lists. Once the user is in the store, they can use it to check off items on the list, put in the price and see the total, with tax.<br>
Users can also save their previous lists to either reuse them, or compare current prices to previous ones.<br>
Future implementations of this page would also allow the user to change the tax rate depending on their location, and include coupons and other discounts in the pricing.</p>
</div>
</body>
</template>
Always add a route for the root.
Items = new Mongo.Collection("items");
Found_items = new Mongo.Collection("found_items");
Router.route('home', {path: '/'}); // Add this route
Router.route('about', {path: '/about'});
BTW, you have a head and body section within your template. That is rendered but does not have an effect in your browser.
Use the following syntax with IR's template helper pathFor:
<ul class="menu">
<li class="menuItem">{{> loginButtons}}</li>
<li class="menuItem">Home</li>
<li class="menuItem">About</li>
</ul>
In order to get your code working, I also fixed a couple of issues:
Removed head and body tags in templates.
Renamed Template.body.helpers to Template.home.helpers.
Renamed Template.body.events to Template.home.events.
Now it is adding new items to the collection and showing items.
you have to add a route with / to call localhost:3000
routing example
Router.configure({
layoutTemplate: 'layout',
});
Router.route('/', function () {
this.render('home');
},{
name: 'home'
});
Router.route('/about', function () {
this.render('about');
},{
name: 'about'
});
html
<template name="layout">
{{> yield}}
</template>
<template name="home">
<p>i am the homepage</p>
</template>
<template name="about">
<p>i am the about page</p>
</template>
I'm building an app with two views: home & view list
When the user clicks on a list's name on the home view, it should change to the "view list" template. I've added a session variable called 'view', setting it to 'home' on startup. When a click event is detected on one of the items (list name) on the home screen, it changes the value of view to 'viewList'. Then in the HTML, I have an if statement to show the home template if 'view' is 'home', otherwise show the 'viewList' template.
I can tell the first part works because I'm outputting the value of 'view' and it does output the value "viewList" when you click on a list name, it just doesn't change the template.
What am I missing?
My code:
mylists.js:
Lists = new Mongo.Collection("lists");
if (Meteor.isClient) {
Meteor.startup( function() {
Session.set("view", "home");
});
Template.main.helpers({
view: function () {
return Session.get("view");
}
});
Template.home.helpers({
lists: function () {
return Lists.find({}, {sort: {lastUsed: -1}});
}
});
Template.home.events({
"submit #new-list": function (event) {
var name = event.target.listName.value;
Lists.insert ({
name: name,
createdAt: new Date(),
lastUsed: new Date()
});
},
"click .list-row": function (event) {
Session.set("view", "viewList");
}
});
}
mylists.html:
<head>
<title>My Lists</title>
</head>
<body>
{{> main}}
</body>
<template name="main">
{{view}}
{{#if view "home"}}
{{> home}}
{{else}}
{{> viewList}}
{{/if}}
</template>
<template name="home">
<header>
<h2>My Lists</h2>
</header>
<ul id="lists">
<li>
<form id="new-list">
<input type="text" name="listName" value="My List 1">
<input type="submit" value="Save">
</form>
</li>
{{#each lists}}
{{> list}}
{{/each}}
</ul>
</template>
<template name="viewList">
<header>
<h2>View List</h2>
</header>
<!-- list details will show here -->
</template>
<template name="list">
<li class="list-row" id="{{_id}}">{{name}}</li>
</template>
If you want to change from templates view i suggest you tu install the iron:router package.
run
meteor add iron:router
lester create the routes.js on the /lib folder
now lets do this step by step.
First create 1 template on myAppName/client/views/layout.html
<template name="layout">
{{> yield}}
</template>
and update the routes.js with this code.
Router.configure({
layoutTemplate: 'layout' // here we say that layout template will be our main layout
});
Now on the same routes.js create this 2 routes.
Router.route('/home', function () {
this.render('home');
});
Router.route('/viewList', function () {
this.render('viewList');
});
With this if you navigate to localhost:3000/home or /viewList you will see the html content on there.
NOTES: <header> inside the templates you don't need it.
Now this is just an example because i don't really know whats your main idea here.
you are calling {{#each lists}} inside the home template, so whats the point of having the viewList template?
Now if you want to create individual and dynamic routes for each list you can try this.
Router.map(function () {
this.route('listViews', {
path: '/listViews/:_id',
waitOn: function(){
return Meteor.subscribe('lists')
},
data: function(){
return Lists.findOne({_id: this.params._id});
}
});
});
Now with this, you have dynamic templates for each object on the List collection, if you go to localhost:300/listView/35dwq358ew for example you will get render the listView with some data.
you can do stuff like this inside the template list
<template name="list">
<li class="list-row" id="{{_id}}">{{name}}</li>
<li>Check this List in detail</li>
</template>
and the viewList template will look like this.
<template name="viewList">
<h2>{{title}}</h2>
<!-- list details will show here -->
{{informationAboutList}}
</template>
I'm trying to append text to an already rendered Handlebars page dynamically, so I don't want to have to reload the entire page:
<script id="post-template" type="text/x-handlebars-template">
{{#each blogPost}}
<article>
<h1 class="blog-post-title">{{title}}</h1>
<div class="blog-post-info">
<p class="blog-post-text">{{{post}}}</p>
</div>
{{> comments}}
</article>
{{/each}}
</script>
<script id="comment-template" type="text/x-handlebars-template">
{{#if comments}}
<p class="lead">Comments</p>
{{#each comments}}
<div class="comment-info">
<span>By: {{name}}</span>
<time>Time: {{time}}</time>
</div>
<p>{{body}}</p>
<hr>
{{/each}}
{{/if}}
</script>
So, each time someone adds a comment, I was hoping to load just that. Here's my js:
This renders the page:
$.get('/render-post', function(data){
var source = $("#post-template").html();
var template = Handlebars.compile(source);
$('.posts').html(template({blogPost : data}));
});
And this is what I'm trying to do on a comment:
$.post('/add-comment', commentData, function(data){
if(data){
var source = $("#comment-partial").html();
var template = Handlebars.compile(source);
console.log(template({blogPost : data}));
$('.posts').append(template({blogPost : data}));
}
});
Thank you for any help you can offer.