I am trying to convert the Meteor tutorial app, simple-todo, into a forum. I have a list that populates with Topics with a delete button and a radio button.
What I want to do, is when a Topic's radio button is selected, display all the comments associated with it. I am trying to accomplish this by putting the topicId(originally taskId), used in the tutorial, in a new Collection called Comments. I then query the Comments for that topicId.the comments are mostly copied and pasted topics, so the attributes and functionality of the two is mostly the same.
I, right now, don't know how to get to the topicId from my Template.body.events. If you can help me tie these two DB's together, that would be very helpful.
HTML:
<head>
<title>Forum</title>
</head>
<body>
<div class="login">
{{> loginButtons}}
</div>
<nav class="mainMenu">
<ul>
<li>Home</li>
<li>Forum</li>
<li>About Us</li>
</ul>
</nav>
<div class="container">
<header>
<h1>Forum</h1>
<h2>Post a topic</h2>
{{#if currentUser}}
<form class="new-topic">
<input type="topicalContent" name="topicalContent" placeholder="Type to add new topics" />
</form>
{{/if}}
</header>
<table>
<td class="topicsCol">
<h3>Topics</h3>
<ul class="topicsList">
{{#each topics}}
{{> topic}}
{{/each}}
</ul>
</td>
<td class="commentsCol">
<h3>Comments</h3>
<ul class="commentsList">
{{#each comments}}
{{> comment}}
{{/each}}
</ul>
<input type="commentContent" name="commentContent" placeholder="Type to Comment" />
</td>
</table>
</div>
</body>
<template name="topic">
<li class="{{#if selected}}select{{/if}}">
<button class="delete">×</button>
<span class="topicalContent">{{topicalContent}} -<strong>{{username}}</strong></span>
<input type="radio" name="curTopic" value="{{curTopic}}" />
</li>
</template>
<template name="commentsList">
<li class="comment">
<button class="delete">×</button>
<span class="responseContent">
<strong>
<!-- {{#if username === owner}}
<style="color:red;">OP
{{else}}-->
{{username}}
<!--{{/if}}-->
</strong>: {{responseContent}}</span>
</li>
</template>
JavaScript:
Topics = new Mongo.Collection("topics");
Comments = new Mongo.Collection("comments");
if(Meteor.isServer){
Meteor.publish("topics", function(){
return Topics.find({
$or: [
{ owner: this.userId }
]
});
});
Meteor.publish("comments", function(){
return Comments.find({
$or: [
{ parent: topicId },
{ owner: this.userId }
]
});
});
}
if (Meteor.isClient) {
// This code only runs on the client
Meteor.subscribe("topics");
Meteor.subscribe("comments");
Template.body.helpers({
topics: function() {
return Topics.find({}, {sort: {createdAt: -1}});
},
comments: function () {
return Comments.find({parent: {parent: topicId}}, {sort: {createdAt: -1}});
}
});
Template.body.events({
"submit .new-topic": function (event) {
//Prevent default browser form submit
event.preventDefault();
//Get value from form element
var topicalContent = event.target.topicalContent.value;
if (topicalContent == "") {
throw new Meteor.Error("Empty Input");
}
//Insert a topic into the collection
Meteor.call("addTopic", topicalContent);
//Clear form
event.target.topicalContent.value = "";
},
"submit .commentContent": function (event) {
event.preventDefault();
var commentContent = event.target.commentContent.value;
Meteor.call("addComment", this.topicId);
event.target.commentContent.value= "";
}
});
Template.topic.helpers({
isOwner: function(){
return this.owner === Meteor.userId();
}
});
Template.topic.events({
"click .curTopic": function() {
//Show Comments of selected radio button
Meteor.call("showComments", this._id);
},
"click .delete":function () {
Meteor.call("deleteTopic", this._id);
}
});
Template.comment.helpers({
isOwner: function(){
return this.owner === Meteor.userId();
}
});
Template.comment.events({
"click .delete":function () {
Meteor.call("deleteComment", this._id);
}
});
Accounts.ui.config({
passwordSignupFields: "USERNAME_ONLY"
});
}
Meteor.methods({
addTopic:function(topicalContent){
if (!Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
Topics.insert({
topicalContent,
createdAt: new Date(),
owner: Meteor.userId(),
username: Meteor.user().username
});
},
deleteTopic:function(topicId) {
var topic = Topics.findOne(topicId);
if (topic.owner !== Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
else {
Topics.remove(topicId);
}
},
showComments:function (topicId) {
Comments.find({"parent":topicId});
},
addComment:function(commentContent, topicId){
if (!Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
Comments.insert({
commentContent,
createdAt: new Date(),
owner: Meteor.userId(),
username: Meteor.user().username,
parent: topicId
});
},
deleteComment:function(commentId) {
var comment = Comments.findOne(commentId);
if (comment.owner !== Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
else {
Comments.remove(commentId);
}
}
});
One way (and there are many) is to use a session variable to track the current topic. In your topic event handler:
Template.topic.events({
"click .curTopic": function() {
Session.set('topicId',this._id); // set the Session variable
Meteor.call("showComments", this._id);
});
Now everywhere else you're looking for the current topicId you can just use Session.get('topicId');
Related
I am following the tutorial here, which is about setting session variables in meteorjs.
But I can't get the example to work. Clicking on hide button doesn't do anything.
JS:
Tasks = new Mongo.Collection("tasks");
if (Meteor.isClient) {
// This code only runs on the client
Template.body.helpers({
tasks: function(){
console.log("function called");
if (Session.get("hideCompleted")) {
// If hide completed is checked, filter tasks
console.log("success!");
return Tasks.find({checked: {$ne: true}}, {sort: {createdAt: -1}});
} else {
console.log("failure!");
// Otherwise, return all of the tasks
return Tasks.find({}, {sort: {createdAt: -1}});
}
},
hideCompleted: function () {
return Session.get("hideCompleted"); }
});
Template.body.events({
"submit .new-task": function (event) {
// Prevent default browser form submit
event.preventDefault();
// Get value from form element
var text = event.target.text.value;
// Insert a task into the collection
Tasks.insert({
text: text,
createdAt: new Date() // current time
});
// Clear form
event.target.text.value = "";
}
});
Template.task.events({
"click .toggle-checked": function () {
// Set the checked property to the opposite of its current value
Tasks.update(this._id, {
$set: {checked: ! this.checked}
});
},
"click .delete": function () {
Tasks.remove(this._id);
},
"change .hide-completed input": function (event) {
console.log("Changed!");
Session.set("hideCompleted", event.target.checked);
}
});
}
HTML:
<head>
<title>Todo List</title>
</head>
<body>
<div class="container">
<header>
<h1>Todo List </h1>
<label class="hide-completed">
<input type="checkbox" checked="{{hideCompleted}}" />
Hide Completed Tasks
</label>
<form class="new-task">
<h2> Add a task </h2>
<input type="text" name="text" placeholder="Type to add new tasks" />
</form>
</header>
<ul>
{{#each tasks}}
{{> task}}
{{/each}}
</ul>
</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>
At the beginning my console output is as expected:
function called
failure!
But on clicking the hide-completed checkbox, no event is triggered (i.e., console log doesnt change). What have I missed?
I would say that it is probably because you defined your "toggle checked" handler in the Template.task.events , indeed your checkbox is not part of the "task" template.
Put your handler in the body events, and it should be called properly.
I am working on the Meteortips' Your Second Meteor Application tutorial, and I am at the end of Chapter 5: Routing, Part 2.
When I go to http://localhost:3000/ I get the following screen:
And when I check the Chrome console, I get the following error:
Uncaught TypeError: Cannot read property 'events' of undefined todos.js:85
Here is the content of my todos.js file:
Todos = new Meteor.Collection('todos');
Lists = new Meteor.Collection('lists');
if(Meteor.isClient){
// client code goes here
Template.todos.helpers({
'todo': function(){
var currentList = this._id;
return Todos.find({ listId: currentList }, {sort: {createdAt: -1}})
}
});
Template.addTodo.events({
'submit form': function(event){
event.preventDefault();
var todoName = $('[name="todoName"]').val();
var currentList = this._id;
Todos.insert({
name: todoName,
completed: false,
createdAt: new Date(),
listId: currentList
});
$('[name="todoName"]').val('');
}
});
Template.todoItem.events({
// events go here
'click .delete-todo': function(event){
event.preventDefault();
var documentId = this._id;
var confirm = window.confirm("Delete this task?");
if(confirm){
Todos.remove({ _id: documentId });
}
},
'keyup [name=todoItem]': function(event){
if(event.which == 13 || event.which == 27){
$(event.target).blur();
} else {
var documentId = this._id;
var todoItem = $(event.target).val();
Todos.update({ _id: documentId }, {$set: { name: todoItem }});
}
},
'change [type=checkbox]': function(){
var documentId = this._id;
var isCompleted = this.completed;
if(isCompleted){
Todos.update({ _id: documentId }, {$set: { completed: false }});
console.log("Task marked as incomplete.");
} else {
Todos.update({ _id: documentId }, {$set: { completed: true }});
console.log("Task marked as complete.");
}
}
});
Template.todoItem.helpers({
'checked': function(){
var isCompleted = this.completed;
if(isCompleted){
return "checked";
} else {
return "";
}
}
});
Template.todosCount.helpers({
'totalTodos': function(){
var currentList = this._id;
return Todos.find({ listId: currentList }).count();
},
'completedTodos': function(){
var currentList = this._id;
return Todos.find({ listId: currentList, completed: true }).count();
}
});
Template.addList.events({
'submit form': function(event){
event.preventDefault();
var listName = $('[name=listName]').val();
Lists.insert({
name: listName
}, function(error, results){
Router.go('listPage', { _id: results });
});
$('[name=listName]').val('');
}
});
Template.lists.helpers({
'list': function(){
return Lists.find({}, {sort: {name: 1}});
}
});
}
if(Meteor.isServer){
// server code goes here
}
Router.route('/register');
Router.route('/login');
Router.route('/', {
name: 'home',
template: 'home'
});
Router.route('/list/:_id', {
name: 'listPage',
template: 'listPage',
data: function(){
var currentList = this.params._id;
return Lists.findOne({ _id: currentList });
}
});
Router.configure({
layoutTemplate: 'main'
});
And here is the content of my todos.html file:
<!-- Templates -->
<template name="todoItem">
<li class="{{checked}}">
<input type="checkbox" {{checked}}>
<input type="text" value="{{name}}" name="todoItem">
[Delete]
</li>
</template>
<template name="todos">
<p>{{_id}}</p>
{{> addTodo}}
<ul>
{{#each todo}}
{{> todoItem}}
{{/each}}
</ul>
{{> todosCount}}
</template>
<template name="addTodo">
<form>
Create a task:
<input type="text" placeholder="Type a task here..." name="todoName">
</form>
</template>
<template name="todosCount">
{{#if totalTodos}}
<p>You have completed {{completedTodos}} out of {{totalTodos}} tasks.</p>
{{/if}}
</template>
<template name="register">
<h2>Register</h2>
</template>
<template name="login">
<h2>Login</h2>
</template>
<template name="home">
<p>Welcome to the Todos application.</p>
</template>
<template name="main">
<h1>Todos</h1>
{{> navigation}}
{{> lists}}
{{> yield}}
<hr />
<p>Copyright © Todos, 2014-2015.</p>
</template>
<template name="navigation">
<ul>
<li>Home</li>
<li>Register</li>
<li>Login</li>
</ul>
</template>
<template name="lists">
<h2>Lists</h2>
{{> addList}}
<ul>
{{#each list}}
<li>{{name}}</li>
{{/each}}
</ul>
</template>
<template name="listPage">
<h2>Tasks: {{name}}</h2>
{{> todos}}
</template>
I must certainly be doing something wrong, but I cannot figure out what: any clue?
You're trying to setup events on an undeclared template.
You lack an addList template in your HTML.
In my to-do-app I have a static <select> dropdown list, which I like to use to find specific tasks from the database. But how to get it working? I wired up an event and tried to set a variable assortment but it seems the template doesn't get re-rendered with the new values! Please have a look at the fallowing code:
HTML
<head>
<title>eisenhower</title>
</head>
<body>
{{> eisenhower}}
</body>
<template name="eisenhower">
<div class="eisenhower">
<select id="assortment"> <!-- HERE IS THE DROPDOWN LIST -->
<option value="">all tasks</option>
<option value="true">done tasks</option>
<option value="false" selected>undone tasks</option>
</select>
<div>
<h1>{{doTasksCount}} to do</h1>
<ul>
<li><form><input type="input" name="new" section="do" /></form></li>
{{#each doTasks}}
<li><input type="checkbox" checked="{{checked}}" /> {{task}}</li>
{{/each}}
</ul>
</div>
<div>
<h1>{{scheduleTasksCount}} to schedule</h1>
<ul>
<li><form><input type="input" name="new" section="schedule" /></form></li>
{{#each scheduleTasks}}
<li><input type="checkbox" checked="{{checked}}" /> {{task}}</li>
{{/each}}
</ul>
</div>
<div>
<h1>{{delegateTasksCount}} to delegate</h1>
<ul>
<li><form><input type="input" name="new" section="delegate" /></form></li>
{{#each delegateTasks}}
<li><input type="checkbox" checked="{{checked}}" /> {{task}}</li>
{{/each}}
</ul>
</div>
<div>
<h1>{{abandonTasksCount}} to abandon</h1>
<ul>
<li><form><input type="input" name="new" section="abandon" /></form></li>
{{#each abandonTasks}}
<li><input type="checkbox" checked="{{checked}}" /> {{task}}</li>
{{/each}}
</ul>
</div>
</div>
</template>
JS
Tasks = new Mongo.Collection("tasks");
assortment = true; // HERE IS MY VARIABLE FOR CHANGING THE .find() CLAUSE!
if (Meteor.isClient) {
Template.eisenhower.helpers({
//tasks
doTasks: function() {
return Tasks.find({section: "do", done: assortment}, {sort: {createdAt: -1}});
},
scheduleTasks: function() {
return Tasks.find({section: "schedule", done: assortment}, {sort: {createdAt: -1}});
},
delegateTasks: function() {
return Tasks.find({section: "delegate", done: assortment}, {sort: {createdAt: -1}});
},
abandonTasks: function() {
return Tasks.find({section: "abandon", done: assortment}, {sort: {createdAt: -1}});
},
checked: function() {
return Tasks.findOne(this._id).done;
},
//tasks counter
//doTasksCount: function() { return dos.count(); },
//scheduleTasksCount: function() { return schedules.count(); },
//delegateTasksCount: function() { return delegates.count(); },
//abandonTasksCount: function() { return abandons.count(); },
});
Template.eisenhower.events({
"submit form": function(event, template) {
event.preventDefault();
var obj = event.target.new; //input reference
var task = obj.value;
var section = obj.getAttribute("section"); //obj.section doesnt work here
Tasks.insert({task: task, section: section, done: false, createdAt: new Date()}, function(error, id) {
if(!error) {
event.target.new.value = ""; //clear form
}
});
},
"change checkbox": function(event) {
Tasks.update(this._id, {$set: {done: event.target.checked}});
},
"change select": function(event) {
assortment = (event.target.value) ? event.target.value : true; // SET VARIABLE! BUT DATA DOESNT CHANGE THOUGH!?
}
});
}
The key to get this working is to change the assortment variable to a reactive data source. When a reactive data source is reset in Meteor, the functions depending on it are rerun. When a plain vanilla variable is reset, functions are not rerun.
Your two options here are to make assortment a Session key, or to make it a ReactiveVar. You should take a look at the documentation for each and choose the one that fits best for you:
http://docs.meteor.com/#/full/session
http://docs.meteor.com/#/full/reactivevar
There are some noteworthy differences between the two, e.g., ReactiveVar requires a package to be installed and will not rerun when the value is reset to the same value as existed previously. But to demonstrate the pattern with Session, you will want to set it initially:
Session.setDefault('assortment', true);
In your template helpers, get the value:
doTasks: function() {
return Tasks.find({section: "do", done: Session.get('assortment')}, {sort: {createdAt: -1}});
}
And set it in your template event:
"change select": function(event) {
var assortment = (event.target.value) ? event.target.value : true;
Session.set('assortment', assortment);
}
I'm working on ember.js tutorial now. I got a problem on "adding child routes" chapter. My todos list is not displayed. The "todos" template outputing just fine but "todos/index" template doesn't work at all. The console does not show any errors. I guess that this is some local problem or some bug. Maybe someone has already met with a similar problem. What could be the reason of this issue? How can i solve it?
Thanks.
HTML:
<html>
<head>
<meta charset="utf-8">
<title>Ember.js • TodoMVC</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script type="text/x-handlebars" data-template-name="todos/index">
<ul id="todo-list">
{{#each itemController="todo"}}
<li {{bind-attr class="isCompleted:completed isEditing:editing"}}>
{{#if isEditing}}
{{edit-todo class="edit" value=title focus-out="acceptChanges" insert-newline="acceptChanges"}}
{{else}}
{{input type="checkbox" checked=isCompleted class="toggle"}}
<label {{action "editTodo" on="doubleClick"}}>{{title}}</label><button {{action "removeTodo"}} class="destroy"></button>
{{/if}}
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="todos">
<section id="todoapp">
<header id="header">
<h1>todos</h1>
{{input type="text" id="new-todo" placeholder="What needs to be done?"
value=newTitle action="createTodo"}}
</header>
<section id="main">
{{outlet}}
<input type="checkbox" id="toggle-all">
</section>
<footer id="footer">
<span id="todo-count">
<strong>{{remaining}}</strong> {{inflection}} left</span>
<ul id="filters">
<li>
All
</li>
<li>
Active
</li>
<li>
Completed
</li>
</ul>
<button id="clear-completed">
Clear completed (1)
</button>
</footer>
</section>
<footer id="info">
<p>Double-click to edit a todo</p>
</footer>
</script>
<script src="js/libs/jquery-1.10.2.js"></script>
<script src="js/libs/handlebars-1.1.2.js"></script>
<script src="js/libs/ember-1.2.0.js"></script>
<script src="js/libs/ember-data.js"></script>
<script src="js/app.js"></script>
<script src="js/route.js"></script>
<script src="js/models/todo.js"></script>
<script src="js/controllers/todo_controller.js"></script>
<script src="js/controllers/todos_controller.js"></script>
<script src="js/views/edit_todo_view.js"></script>
</body>
</html>
JS:
window.Todos = Ember.Application.create();
Todos.ApplicationAdapter = DS.FixtureAdapter.extend();
Todos.Router.reopen({
rootURL: '/one/'
});
Todos.Router.map(function () {
this.resource('todos', { path: '/' });
});
Todos.TodosRoute = Ember.Route.extend({
model: function () {
return this.store.find('todo');
}
});
Todos.TodosIndexRoute = Ember.Route.extend({
model: function () {
return this.modelFor('todos');
}
});
Todos.Todo = DS.Model.extend({
title:DS.attr('string'),
isCompleted:DS.attr('boolean')
});
Todos.Todo.FIXTURES = [
{
id: 1,
title: 'Learn Ember.js',
isCompleted: true
},
{
id: 2,
title: '...',
isCompleted: false
},
{
id: 3,
title: 'Profit!',
isCompleted: false
}
];
Todos.TodosController = Ember.ArrayController.extend({
actions: {
createTodo: function () {
// Get the todo title set by the "New Todo" text field
var title = this.get('newTitle');
if (!title.trim()) { return; }
// Create the new Todo model
var todo = this.store.createRecord('todo', {
title: title,
isCompleted: false
});
// Clear the "New Todo" text field
this.set('newTitle', '');
// Save the new model
todo.save();
}
},
remaining: function () {
return this.filterBy('isCompleted', false).get('length');
}.property('#each.isCompleted'),
inflection: function () {
var remaining = this.get('remaining');
return remaining === 1 ? 'item' : 'items';
}.property('remaining'),
});
Todos.TodoController = Ember.ObjectController.extend({
actions:{
editTodo: function () {
this.set('isEditing', true);
},
acceptChanges: function () {
this.set('isEditing', false);
if (Ember.isEmpty(this.get('model.title'))) {
this.send('removeTodo');
} else {
this.get('model').save();
}
},
removeTodo: function () {
var todo = this.get('model');
todo.deleteRecord();
todo.save();
},
},
isEditing: false,
isCompleted: function(key, value){
var model = this.get('model');
if (value === undefined) {
// property being used as a getter
return model.get('isCompleted');
} else {
// property being used as a setter
model.set('isCompleted', value);
model.save();
return value;
}
}.property('model.isCompleted')
});
Technically this isn't a bug, the team figured there is no point in having an index route if you can't go any deeper in the router (this is due to the fact that the todos route and template will render, so there is no real need for the index route. That being said, if you really want it, add an anonymous function and you'll get it.
Todos.Router.map(function () {
this.resource('todos', { path: '/' },function () {});
});
https://github.com/emberjs/ember.js/issues/3995
I had this problem too. After much perplexity, the solution was to use a version of index.html that actually had the <script> wrapped <ul>, instead of the one where I was moving that block around to see if it made a difference and ended up having it nowhere.
New Meteor User.
Wanting to modify the leaderboard example for a story sizing tool where members in a team can rate a story simultaneously.
Very similar to leaderboard, but want to add a flag/event/button for an admin user to be able to turn on and off the leaderboard displayed.
Here is my feeble attempt at this -
// Set up a collection to contain member information. On the server,'
// it is backed by a MongoDB collection named "members".
Members = new Meteor.Collection("members");
Flags = new Meteor.Collection("Flags");
if (Meteor.isClient) {
Meteor.startup(function() {
Session.set("viewall", false);
});
Template.leaderboard.members = function () {
if (Session.get("viewall"))
{
return Members.find({}, {sort: {score: -1, name: 1}});
}
};
Template.size.members = function() {
return Members.find({}, {sort: {name: 1}});
};
Template.size.events ({
'click input.submit': function(){
var memname = document.getElementById('select_member').value;
//alert(memname);
var member = Members.findOne({_id: memname});
if(member._id)
{
Session.set("selected_player", member._id);
//alert(member.name);
}
var memsize = document.getElementById('select_size').value;
alert(memsize);
Members.update(Session.get("selected_player"), {$set: {score: memsize}});
}
});
Template.leaderboard.isAdmin = function() {
var member=Members.findOne(Session.get("selected_player"));
var memtype = member.utype;
if (memtype=== "admin")
{
return true;
}
else
{
return false;
}
};
Template.leaderboard.selected_name = function () {
var member = Members.findOne(Session.get("selected_player"));
return member && member.name;
};
Template.leaderboard.viewAll = function() {
var flag = Flags.findOne({name:"showAll"});
if (flag)
{
alert("View All flag set for current user : " + flag.value);
return flag && flag.value;
}
else return false;
};
Template.leaderboard.selected_size = function () {
var member = Members.findOne(Session.get("selected_player"));
return member && member.score;
};
Template.member.selected = function () {
return Session.equals("selected_player", this._id) ? "selected" : '';
};
Template.leaderboard.events({
'click input.inc1': function () {
alert('setting it to 1');
updatePrevScore();
// Members.find({_id: Session.get("selected_player")}).foreach(function(doc){
// doc.prev_score = doc.score;
// Member.save(doc);
// });
//Members.update(Session.get("selected_player"), {$set: {prev_score: score}});
Members.update(Session.get("selected_player"), {$set: {score: 1}});
},
'click input.inc2': function () {
updatePrevScore();
Members.update(Session.get("selected_player"), {$set: {score: 2}});
},
'click input.inc3': function () {
updatePrevScore();
Members.update(Session.get("selected_player"), {$set: {score: 3}});
},
'click input.inc5': function () {
updatePrevScore();
Members.update(Session.get("selected_player"), {$set: {score: 5}});
},
'click input.inc8': function () {
updatePrevScore();
Members.update(Session.get("selected_player"), {$set: {score: 8}});
},
'click input.inc13': function () {
updatePrevScore();
Members.update(Session.get("selected_player"), {$set: {score: 13}});
},
'click input.inc20': function(){
updatePrevScore();
Members.update(Session.get("selected_player"),{$set: {score:20}});
},
'click input.reset': function(){
if (confirm('Are you sure you want to reset the points?')) {
resetScores();
}
},
'click input.showAll': function() {
setFlag();
},
'click input.hideAll': function() {
resetFlag();
}
});
Template.member.events({
'click': function () {
Session.set("selected_player", this._id);
}
});
function resetFlag() {
Meteor.call("resetFlag", function(error, value) {
Session.set("viewall", false);
});
};
function setFlag() {
Meteor.call("setFlag", function(error, value) {
Session.set("viewall", true);
});
};
function resetScores() {
//alert('resetting scores');
Members.find().forEach(function (member) {
Members.update(member._id, {$set: {prev_score: member.score}});
Members.update(member._id, {$set: {score: 0}});
});
Session.set("selected_player", undefined);
};
function updatePrevScore() {
//alert('resetting scores');
Members.find().forEach(function (member) {
if (member._id === Session.get("selected_player"))
{
Members.update(member._id, {$set: {prev_score: member.score}});
Members.update(member._id, {$set: {score: 0}});
}
});
};
}
// On server startup, create some members if the database is empty.
if (Meteor.isServer) {
Members.remove({});
Meteor.startup(function () {
if (Members.find().count() === 0) {
var names = ["Member 1",
"Member 2",
"Member 3",
"Member 4",
"Member 5"
];
var type;
for (var i = 0; i < names.length; i++)
{
if (i===0)
type = "admin";
else
type="user";
Members.insert({name: names[i], score: 0, prev_score:0, utype:type});
}
}
else resetScores();
if (Flags.find().count() === 0) {
Flags.insert({name: "showAll", value: false});
}
else Flags.update({name:"showAll"}, {$set: {value:false}});
}
);
Meteor.methods({
setFlag: function() {
Flags.update({name:"showAll"}, {$set: {value:true}});
console.log("Updated flag to true");
return true;
},
resetFlag: function() {
Flags.update({name:"showAll"}, {$set: {value:false}});
console.log("Updated flag to false");
return false;
},
}
);
HTML =>
<head>
<title>Story Points Exercise</title>
</head>
<body>
<div id="story_id">
Story Sizing for Story ID: 78972
</div>
<div id="outer">
{{> leaderboard}}
</div>
</body>
<template name="size">
<div class="select_member">
<select id="select_member">
{{#each members}}
<option value={{_id}}> {{name}} </option>
{{/each}}
</select>
</div>
<div class="select_size">
<select id="select_size"> Select Size:
<option value=1>1</option>
<option value=2>2</option>
<option value=3>3</option>
<option value=5>5</option>
<option value=8>8</option>
<option value=13>13</option>
<option value=20>20</option>
</select>
</div>
<div class="submitbutton">
<input type="button" class="submit" value="Submit" />
</div>
</template>
<template name="leaderboard">
<div class="leaderboard">
{{#if selected_name}}
<div class="details">
<div class="name">{{selected_name}}</div>
<div class="size">{{selected_size}}</div>
<div class="details">
<input type="button" class="inc1" value="1 points" />
<input type="button" class="inc2" value="2 points" />
<input type="button" class="inc3" value="3 points" />
<input type="button" class="inc5" value="5 points" />
<input type="button" class="inc8" value="8 points" />
<input type="button" class="inc13" value="13 points" />
<input type="button" class="inc20" value="20 points" />
</div>
{{#if isAdmin}}
<input type="button" class="showAll" value="showAll" />
<input type="button" class="hideAll" value="hideAll" />
<input type="button" class="reset" value="Reset"/>
{{/if}}
{{#if viewAll}}
{{#each members}}
{{> member}}
{{/each}}
{{/if}}
</div>
{{/if}}
{{#unless selected_name}}
{{>size}}
{{/unless}}
</div>
</template>
<template name="member">
<div class="member {{selected}}">
<span class="name">{{name}}</span>
<span class="score">{{score}}</span>
<span class="prevscore">{{prev_score}}</span>
</div>
</template>
Its working on one browser and one user (Admin type is able to enable the viewAll flag for the template to show all members.)
But, not working for mulitple users.
So, if I open a browser, select my name and a story size and I am the admin, I click Submit - I see buttons for changing the story size and to showAll, hideAll and Resetting the leaderbaord.
when I click on showAll, I as admin can see the leaderboard. But another user is not able to see the leaderboard. I verified that the change display event (showAll flag=true) is being received by that user's client.
Any ideas?
I was able to solve this by using a new collection called Views and observing for a specific document called showAll.
The showAll was set to be updated by the admin only.
It was hooked up to the template view with an {{#if}}.