Here's my simple template:
<template name="feed">
{{> crewChat}}
{{> statusSubmit}}
{{#each statuses}}
{{> statusItem}}
{{/each}}
</template>
In my groupChat.html and groupChat.js files:
<template name="crewChat">
<div class="post-item">
<div class="ui feed">
{{#each messages}}
{{> crewChatMessage}}
{{/each}}
</div>
</div>
<form class="new-message">
<textarea id="message" name="content" rows="2"></textarea>
<div class="post-actions text-right">
<input type="submit" value="Submit" class="compact tiny ui primary button">
</div>
</form>
</template>
Template.crewChat.events({
'submit form': function(e) {
e.preventDefault();
var crewMessage = {
content: e.target.content.value
}
Meteor.call('createCrewMessage', crewMessage, function(error, result) {
if (error)
return alert(error.reason);
console.log("Create new crew message.");
$(e.target.content).val("");
});
}
});
Template.crewChat.helpers({
messages: function() {
return CrewMessages.find({}, {sort: {submitted: -1}});
}
});
When I submit a new message, I can see it added using Mongol (and visually for a split second), but it's removed immediately after.
Meteor.methods({
createCrewMessage: function(crewMessageAttributes) {
var user = Meteor.user();
var crewMessage = _.extend(crewMessageAttributes, {
userId: user._id,
author: user.profile.firstName,
submitted: new Date()
});
var crewMessageId = CrewMessages.insert(crewMessage);
return { _id: crewMessageId };
}
});
Any ideas why this would be happening?
I had forgotten to subscribe to my published collection.
Meteor.subscribe('crewMessages');
Related
I want to create a simple Login, Register and Logout menu with Meteor and Iron Router. Before I used the Iron Router package I could submit a new user and easily login or logout. Therefore I had this code in my html document:
<body>
{{#if currentUser}}
{{> dashboard}}
{{else}}
{{> register}}<br>
{{> login}}
{{/if}}
</body>
Now I want to route the login and register form. If you press the Login button we should get: lochalhost:3000 login (which works fine).
But I don't know:
why I can't submit a new user anymore
how I can change from the successful login route to the dashboard route
and probably how I can logout (couldn't test it yet)
I'm new to JS and Meteor. Still I didn't find a solution in the Internet or a way to fix it on my own.
My complete document looks like:
main.html:
<head>
<title>Routing</title>
</head>
<body>
{{#if currentUser}}
{{> dashboard}}
<!--{{else}}
{{> register}}<br>
{{> login}} -->
{{/if}}
</body>
<template name="main">
<h1>Text</h1>
{{> navigation}}
{{> yield}}
<hr />
<p>
Copyright ©
</p>
</template>
<template name="home">
<p>
Welcome to the <b>Text</b> website.
</p>
</template>
<template name="navigation">
<ul>
<li>Home</li>
<li>Register</li>
<li>Login</li>
</ul>
</template>
<template name="register">
<form>
<input type="text" id="username">
<input type="text" id="email">
<input type="password" id="password">
<input type="submit" value="Register">
</form>
</template>
<template name="login">
<form>
<input type="text" id="login-email">
<input type="password" id="login-password">
<input type="submit" value="Login">
</form>
</template>
<template name="dashboard">
<p>
Yor're logged in.
Logout
</p>
</template>
main.js
Router.route('register'); // Default name is register
Router.route('login'); // Default name is login
Router.route('dashboard');
Router.route('/', {
name: 'home',
template: 'home'
});
Router.configure({
layoutTemplate: 'main'
});
if (Meteor.isClient) {
Template.register.events({
'submit form': function(event, template) {
event.preventDefault();
var usernameVar = template.find('#username').value;
var emailVar = template.find('#email').value;
var passwordVar = template.find('#password').value;
Accounts.createUser({
username: usernameVar,
email: emailVar,
password: passwordVar
})
}
});
Template.login.events({
'submit form': function(event, template) {
event.preventDefault();
var emailVar = template.find('#login-email').value;
var passwordVar = template.find('#login-password').value;
Meteor.loginWithPassword(emailVar, passwordVar);
}
});
Template.dashboard.events({
'click .logout': function(event) {
event.preventDefault();
Meteor.logout();
prompt("You successfully logged out");
}
});
}
And I added:
the iron:router package
meteor add accounts-ui accounts-password
I would say, do read the official documentation for Iron Router and Meteor to have better understanding. I took your code and did some testing, it works fine. I only added iron:router accounts-ui (Look up documentation for this, you can create easy login and signup with this package) and accounts-password.
main.html
<head>
<title>Routing</title>
</head>
<body>
{{#if currentUser}}
{{> dashboard}}
<!--{{else}}
{{> register}}<br>
{{> login}} -->
{{/if}}
</body>
<template name="main">
<h1>Text</h1>
{{> navigation}}
{{> yield}}
<hr />
<p>
Copyright ©
</p>
</template>
<template name="home">
<p>
Welcome to the <b>Text</b> website.
</p>
</template>
<template name="navigation">
<ul>
<li>Home</li>
{{#unless currentUser}}
<li>Register</li>
<li>Login</li>
{{/unless}}
</ul>
</template>
<template name="register">
{{#unless currentUser}}
<form>
<input type="text" id="username">
<input type="text" id="email">
<input type="password" id="password">
<input type="submit" value="Register">
</form>
{{/unless}}
</template>
<template name="login">
{{#unless currentUser}}
<form>
<input type="text" id="login-email">
<input type="password" id="login-password">
<input type="submit" value="Login">
</form>
{{/unless}}
</template>
<template name="dashboard">
<p>
Yor're logged in.
Logout
</p>
</template>
main.js
goHome =function(){
if(Meteor.userId()){
Router.go('/');
}
}
Router.configure({
layoutTemplate: 'main'
});
Router.route('/register', {
template:'register',
onBeforeAction:function(){
goHome();
this.next();
}
}); // Default name is register
Router.route('/login', {
template:'login',
onBeforeAction:function(){
goHome();
this.next();
}
});
Router.route('/dashboard',{
template:'dashboard'
})
Router.route('/', {
name: 'home',
template: 'home'
});
if (Meteor.isClient) {
Template.register.events({
'submit form': function(event, template) {
event.preventDefault();
var usernameVar = template.find('#username').value;
var emailVar = template.find('#email').value;
var passwordVar = template.find('#password').value;
Accounts.createUser({
username: usernameVar,
email: emailVar,
password: passwordVar
}, function(error){
if(!error){
Router.go('/');
}
})
}
});
Template.login.events({
'submit form': function(event, template) {
event.preventDefault();
var emailVar = template.find('#login-email').value;
var passwordVar = template.find('#login-password').value;
Meteor.loginWithPassword(emailVar, passwordVar, function(error){
if(!error){
Router.go('/');
}
});
}
});
Template.dashboard.events({
'click .logout': function(event) {
event.preventDefault();
Meteor.logout();
prompt("You successfully logged out");
}
});
}
Based on the code below, is there any reason why I am not getting the list of Categories populated, even though the browser console shows 6 when I type Categories.find().count()?
What did I do incorrectly? Here is my repository on GitHub.
categories.js:
Categories = new Mongo.Collection('categories');
if (Meteor.isServer) {
Categories.allow({
insert: function(userId, doc) {
return true;
},
update: function(userId, doc, fieldNames, modifier) {
return true;
},
remove: function(userId, doc) {
return true;
}
});
}
home_controller.js:
HomeController = RouteController.extend({
subscriptions: function() {
this.subscribe('categories');
this.subscribe('photos');
},
data: function () {
console.log(this.params.name);
Session.set('category', this.params.name);
},
action: function () {
this.render('MasterLayout', {});
}
}
list_categories.html:
<template name="ListCategories">
<ul>
{{#each Categories}}
<li id="categories"><a class="btn btn-default" href="/{{name}}">{{name}}</a></li>
{{/each}}
</ul>
</template>
list_categories.js:
Template.ListCategories.helpers({
Categories: function() {
return Categories.find();
}
});
list_photos.html:
<template name="ListPhotos">
<div id='photos'>
<div class='page-header'>
<h1>
<small>
{{#if catnotselected}}
Photos
{{else}}
{{category}} Photos
{{/if}}
</small>
</h1>
</div>
<div id='mainContent'>
{{#each photolist}} {{>photo}} {{else}} {{#if catnotselected}}
<div class='page-header'>
<h1><small>Select a category.</small></h1></div>
{{else}}
<div class='page-header'>
<h1><small>No photos in this category.</small></h1></div>
{{/if}} {{/each}}
</div>
</div>
</template>
list_photos.js:
Template.ListPhotos.helpers({
catnotselected: function() {
return Session.equals('category', null);
},
category: function() {
return Session.get('category');
}
});
master_layout.html:
<template name="MasterLayout">
<div class="navbar">
<div class="container">
<div class="navbar-inner">
<a class="brand btn" href="/"><img style="height: 40px; width: 135px;" src="img/logo.png" />
<p>Photos</p>
</a>
<div id="login-button" class="btn btn-default pull-right">
{{> loginButtons}}
</div>
</div>
</div>
</div>
<div class='container-fluid'>
<div class='row'>
<div class='col-xs-12 text-center'>
{{> yield 'categories'}}
</div>
<div class='col-xs-10 col-xs-offset-1 text-center'>
{{> yield 'photos'}}
</div>
</div>
</div>
</template>
master_layout.js:
Template.MasterLayout.onCreated(function() {
Session.set('category', null);
});
photos.js:
Photos = new Mongo.Collection('photos');
if (Meteor.isServer) {
Photos.allow({
insert: function(userId, doc) {
return true;
},
update: function(userId, doc, fieldNames, modifier) {
return true;
},
remove: function(userId, doc) {
return true;
}
});
}
routes.js:
Router.configure({
layoutTemplate: 'MasterLayout',
loadingTemplate: 'Loading',
notFoundTemplate: 'NotFound',
yieldTemplates: {
'photos': {
to: 'ListPhotos'
},
'categories': {
to: 'ListCategories'
}
}
});
Router.route('/', {
name: 'home',
controller: 'HomeController',
action: 'action',
where: 'client'
});
Router.route('/:name', {
name: 'photos',
controller: 'HomeController',
action: 'action',
where: 'client'
});
As expected, rendering the ListPhotos and ListCategories template fails. That's why there are no corresponding elements in your DOM, even though you can access documents of your Photos and Categories collection via the console.
Apparently, using yieldRegions in the global router config will fail, due to an iron-router issue, which requires to call this.render() in the route's action.
routes.js:
Router.configure({
layoutTemplate: 'MasterLayout',
loadingTemplate: 'Loading',
notFoundTemplate: 'NotFound',
yieldRegions: {
//each yield going to different templates
'ListPhotos': {
to: 'photos'
},
'ListCategories': {
to: 'categories'
}
}
});
Router.route('/', {
name: 'home',
controller: 'HomeController',
action: function () {
this.render();
},
where: 'client'
});
Router.route('/:name', {
name: 'photos',
controller: 'HomeController',
action: function () {
this.render();
},
where: 'client'
});
I've got this html in my Meteor project:
<head>
<title>The Dentist Hurt My Fillings</title>
</head>
<body>
<h2>Thirteen Ways of Looking at a Duckbilled Platypus</h2>
<br/>
<br/>
<div class="container">
{{> whizzardBlizzard}}
</div>
</body>
<template name="whizzardBlizzard">
<form>
{{#if firstStep}}
{{> firstStepTemplate}}
{{/if}}
{{#if secondStep}}
{{> secondStepTemplate}}
{{/if}}
{{#if thirdStep}}
{{> thirdStepTemplate}}
{{/if}}
<input type="submit" value="Submit" class="button">
</form>
</template>
<template name="firstStepTemplate">
<h2>Step 1</h2>
</template>
<template name="secondStepTemplate">
<h2>Step 2</h2>
</template>
<template name="thirdStepTemplate">
<h2>Step 3</h2>
</template>
...and this Javascript:
if (Meteor.isClient) {
// stepNum starts at 1
Session.setDefault('stepNum', 1);
Template.whizzardBlizzard.events({
"submit form": function (event) {
//event.preventDefault();
// save the vals to a new document in a collection
Session.set('stepNum', Session.get('stepNum') + 1);
}
});
Template.whizzardBlizard.helpers({
'firstStep': function() {
return (Session.get('stepNum') == 1);
},
'secondStep': function() {
return (Session.get('stepNum') == 2)
},
'thirdStep': function() {
return (Session.get('stepNum') == 3)
}
// . . . etc.
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
When I try to run it, I get, "Uncaught TypeError: Cannot read property 'helpers' of undefined"?
How could that be? Template helpers are a key component of Meteor, and examples of its usage mirror mine.
I have tried it both with and without encasing the helper name (such as "firstStep") in single quotes; that is, I've tried both this:
firstStep: function() {
..and this:
'firstStep': function() {
...while calling it like so:
{{#if firstStep}}
{{> firstStepTemplate}}
{{/if}}
So why is 'helpers' reportedly unreadable?
Blizzard in your helper only has one "z": Blizard
I'm doing some intro Meteor stuff, and I'm having trouble getting the correct values from my Collection. I'm trying to track ownership of the central site, as claimed by a button. The program is currently just an extension of the Try Meteor task tutorial. Anyways, here's the HTML and JS:
--------------HTML------------
<head>
<title>Todo List</title>
</head>
<body>
<div class="container">
<header>
<h1>Todo List</h1>
<form class="new-task">
<input type="text" name="text" placeholder="Type to add new tasks" />
</form>
{{> ownerclaim}}
<h4>Current owner: {{ownerget}}</h4>
</header>
<u1>
{{#each tasks}}
{{> task}}
{{/each}}
</u1>
{{> loginButtons}}
</div>
</body>
<template name="task">
<li class="{{#if checked}}checked{{/if}}">
<button class="delete">×</button>
<input type="checkbox" checked="{{checked}}" class="toggle-checked" />
<span class="text">{{text}}</span>
</li>
</template>
<template name="ownerclaim">
<button class="claim">Claim website</button>
</template>
<template name="ownership">
<span class="text">{{text}}</span>
</template>
-----------JS---------------
OwnerC = new Mongo.Collection("owner");
Tasks = new Mongo.Collection("tasks");
if (Meteor.isClient) {
Meteor.subscribe("own");
console.log(OwnerC.findOne({}));
Session.set("currentOwner", OwnerC.findOne({}));
Template.body.helpers({
tasks: function () {
return Tasks.find({}, {sort: {createdAt: -1}});
},
ownerget: function () {
console.log("JOHNNN");
console.log(Session.get("currentOwner"));
return Session.get("currentOwner");
}
});
Template.body.events({
"submit .new-task": function (event) {
var text = event.target.text.value;
Tasks.insert({
text: text,
createdAt: new Date(),
owner: Meteor.userId(),
username: Meteor.user().username
});
event.target.text.value = "";
return false;
}
});
Template.task.events({
"click .toggle-checked": function() {
Tasks.update(this._id, {$set: {checked: ! this.checked}});
},
"click .delete": function() {
Tasks.remove(this._id);
}
});
Template.ownerclaim.events({
"click .claim": function() {
OwnerC.update({}, {$set: {text: Meteor.user._id}});
}
})
Accounts.ui.config({
passwordSignupFields: "USERNAME_ONLY"
});
}
if(Meteor.isServer) {
console.log("YOYOYOYOYOYO");
Meteor.startup( function(){
console.log("YOYO");
OwnerC.insert({
text: "none",
createdAt: new Date(),
owner: "0",
username: "0"
});
console.log(OwnerC.findOne({}));
Meteor.publish("own", function() {
return OwnerC.find({});
});
});
}
For some reason, my server logs are showing OwnerC to contain the object, but the client logs are showing it as an empty Collection, and findOne in the client is returning undefined. Anyone know where I'm going wrong?
I have a templates:
<div id="search">
{{> search}}
</div>
<div id="bookmarks-container">
{{> bookmarks}}
</div>
<template name="bookmarks">
{{#each bookmarks}}
<div class="bookmark">
{{URL}}
</div>
{{/each}}
</template>
<template name="search">
<input type="text" id="search" value="" />
</template>
And I have a code to get bookmarks:
bookmarks = new Meteor.Collection("Bookmarks");
if (Meteor.isClient) {
Template.bookmarks.bookmarks = function() {
var s = $('#search').text();
alert(s);
if (s === '')
return bookmarks.find({});
else
return bookmarks.find({tags : 'some_tag'});
};
I want to display all bookmarks if #search text field is empty and filter my bookmarks if it is not.
As I see Template.bookmarks.bookmarks calls only once - when page loaded in the browser. How can I call this method every time when user press the button in the #search text input:
Template.search.events({
'keyup #search' : function(e,t) {
// ....
}
Thanks in advance.
Relay the data with Session
var s = Session.get("query");
and
Template.search.events({
'keyup #search' : function(e,t) {
Session.set("query",t.find('#search').value);
}
On its own the template bookmarks helper wouldn't know when to refresh the data. Using Session tells it that the query variable/hash is reactive.