Having issues with showing collection data in meteor - meteor

I am having collection issues in my Meteor project. I added the following code to my Resolutions.js file:
Resolutions = new Mongo.Collection('resolutions');
if (Meteor.isClient) {
Template.body.helpers({
resolutions: function() {
Resolutions.find({});
}
});
Template.body.events({
'submit .new-resolution': function(event) {
var title = event.target.title.value;
Resolutions.insert({
title: title,
createdAt: new Date()
});
event.target.title.value = "";
return false;
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
and added the following to my Resolutions.html file:
<head>
<title>Resolutions</title>
</head>
<body>
<div class="container">
<header>
<h1>Monthly Resolutions</h1>
<form class="new-resolution">
<input type="text" name="title" placeholder="A new resolution" />
<input type="submit" value="Submit"/>
</form>
</header>
<ul>
{{#each resolutions}}
{{> resolution}}
{{/each}}
</ul>
</div>
</body>
<template name="resolution">
<li>{{title}}</li>
</template>
After running the app I get zero errors but still the site does not return any of the collection value. I have no clue what is wrong with this project.

Template.body.helpers({
resolutions: function() {
return Resolutions.find({});
}
});
You forgot to use the return keyword.Remember that when creating a helper, you always need to return a value.

Related

Meteor not adding and showing tasks in web page, it just blinks and malfunctions (To create Todos list to add and delete tasks)

//Client side code in client\main.js
Tasks=new Mongo.Collection('tasks');
Template.tasks.helpers({
tasks:function () {
return Tasks.find({},{sort:{createdAt:-1}});
}
});
Template.tasks.events({
"submit .add-task":function (event) {
var name = event.target.name.value;
Meteor.call('addTask',name);
event.target.name.value='';
return false;
},
"click .delete-task":function (event) {
if(confirm('Delete Task?')){
Meteor.call('deleteTask',this._id);
}
return false;
}
});
Meteor.methods({
addTask: function (name) {
if (!Meteor.userId()) {
throw new Meteor.Error('No Access!!');
}
Tasks.insert({
name: name,
createdAt: new Date(),
userId: Meteor.userId()
});
},
deleteTask: function(taskId) {
Tasks.remove(taskId);
}
});
//Server side code in server\main.js
Tasks=new Mongo.Collection('tasks');
Meteor.methods({
addTask: function (name) {
if (!Meteor.userId()) {
throw new Meteor.Error('No Access!!');
}
Tasks.insert({
name: name,
createdAt: new Date(),
userId: Meteor.userId()
});
},
deleteTask: function taskId() {
Tasks.remove(taskId);
}
});
//Html page
<head>
<title>tasklist</title>
</head>
<body>
{{> tasks}}
</body>
<template name="tasks">
{{> loginButtons}}
<h1>Add Task</h1>
{{#if currentUser}}
<form class="add-task">
<label>Task Name</label>
<input type="text" name="name" placeholder="Add Task" />
<input type="submit" value="Submit" />
</form>
{{else}}
<p>Please log in to add tasks</p>
{{/if}}
<hr />
<h3>Tasks</h3>
<ul>
{{#each tasks}}
<li>{{name}}{{#if currentUser}} X{{/if}} </li>
{{/each}}
</ul>
</template>
Please help, in this when i reload page it first add and and shows in the web-page and if i delete the try todelete the added then screen doesnot show even added tasks which are in MongoDB.
And when i do console, there is an empty array of added tasks
If it "blinks" this often means that your Method worked client side but not server side. The insert worked on your Minimongo (client) but not on the real MongoDB (server). So Meteor decide to rollback your insert on Minimongo.
You must have a problem inside your Method server side:
You can't use Meteor.userId() server side in your Methods, you have to use this.userId.
To avoid mistakes, only use this.userId inside the Meteor Methods client or server side.
// Server side
Meteor.methods({
addTask: function (name) {
if (!this.userId) {
throw new Meteor.Error('No Access!!');
}
Tasks.insert({
name: name,
createdAt: new Date(),
userId: this.userId
});
},
deleteTask: function taskId() {
Tasks.remove(taskId);
}
});
In Meteor, you don't have to duplicate your Methods client AND server side.
Methods should always be defined in common code loaded on the client and the server to enable Optimistic UI.
You just have to define your Methods and your collection one time inside a folder loaded on client and server. For exemple you can put your code inside a folder named both/.

Meteor : create a search (filter) without using autopublish

I have a search facility in my project and I need to be able to publish results without using autopublish.
html
<template name="search">
<form id="searchform">
<input type="text" id="kategori" placeholder="Sila masukkan maklumat carian."/>
<button>Carian</button>
</form>
<hr/>
<h3>Maklumat</h3>
<ol>
{{#each profil}}
<li>{{jenama}}</li>
{{/each}}
</ol>
</template>
js:
Template.search.events({
"submit #searchform": function (e) {
e.preventDefault();
Session.set("kategori", e.target.text.value);
}
});
Template.search.helpers({
profil: function() {
return Profil.find({
kategori: Session.get('kategori'),
});
}
});
You can simply subscribe to a filtered publication:
client:
Template.search.events({
"submit #searchform": function (e) {
e.preventDefault();
Session.set("kategori", e.target.text.value);
Meteor.subscribe('profiles',Session.get('kategori'));
}
});
server:
Meteor.publish('profiles',function(kategori){
return Profil.find({ kategori: kategori });
});
If you don't have any other subscriptions to the same collection you can also simplify your helper to:
Template.search.helpers({
profil: function() {
return Profil.find();
}
});
Since the set of documents will be defined by your publication.
In practice though you usually use the same search in your helper as you do in the publication just to avoid documents from other publications showing up.

Limiting each inside of each based on context

Having trouble trying to pass some sort of context into my little test chan-clone.
Problem is I have threads, with replies. Showing just the threads works great, showing threads with replies based upon the threads they come from not so much.
Question is how do I send context on the outer each. Thank you so much for the help!
meteorchan.html
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</head>
<body>
<h1>Meteor Chan - Let's do this</h1>
<form class="new-thread">
<input type="text" name="text" placeholder="New Thread" />
<button>Submit</button>
</form>
<br/>
{{#each threads}}
{{> thread}}
{{#each replies}}
{{> reply}}
{{/each}}
{{/each}}
</body>
<template name="thread">
<div class="thread">
<span>Anonymous</span> No. {{iden}}
<br>
{{text}}
</div>
<a class="reply" href="#">Reply</a> : <button class="purge">Purge</button>
<form class="new-reply {{this._id}}" style="display:none;">
<input type="text" name="text" placeholder="Add Reply" />
<input type="text" name="thread" value="{{this._id}}" style="display:none;" />
<button>Add New Reply</button>
</form>
<br>
<br>
</template>
<template name="reply">
<div class="reply">
{{text}}
<br>
{{parentThread}}
</div>
</template>
meteorchan.js
Threads = new Mongo.Collection("threads");
Replies = new Mongo.Collection("replies");
if (Meteor.isClient) {
Meteor.subscribe("threads");
Template.body.helpers({
threads: function () {
return Threads.find({}, {sort: {createdAt: -1}});
},
replies: function () {
return Replies.find({}, {sort: {createdAt: 1}});
}
});
Template.body.events({
"submit .new-thread": function (event) {
event.preventDefault();
var text = event.target.text.value;
var currentId = 0;
if(Threads.findOne({}, {sort: {createdAt: -1}})){
currentId = Threads.findOne({}, {sort: {createdAt: -1}}).iden;
}
Threads.insert({
text: text,
createdAt: new Date(),
iden: currentId + 1
});
event.target.text.value = "";
},
"submit .new-reply": function (event) {
event.preventDefault();
var text = event.target.text.value;
var thread = event.target.thread.value;
Replies.insert({
text: text,
createdAt: new Date(),
parentThread: thread
});
event.target.text.value = "";
}
});
Template.thread.events({
"click .purge": function (){
Threads.remove(this._id);
},
"submit .new-reply": function(event){
event.preventDefault();
},
"click .reply": function(){
$('.'+this._id+'.new-reply').css('display','inherit');
}
});
}
if (Meteor.isServer) {
Meteor.publish("threads", function () {
return Threads.find();
});
Meteor.publish("replies", function () {
return Replies.find();
});
}
You can refer to the context in the template helper using this.
So in your replies helper this refers to the current thread you are iterating over using the each.
You can do the following to only fetch replies for the corresponding thread:
replies: function () {
return Replies.find({
// this refers to the current thread
parentThread: this._id
}, {sort: {createdAt: 1}});
}

Meteor: collection empty after insert

I am new to meteor and got stucked and can't understand what am I doing wrong. Enlighten me please.
Here is the HTML file:
<body>
<h1>Do</h1>
{{#if activeTask}}
{{> currentTask}}
{{else}}
{{> newTask }}
{{/if}}
<div>
</div>
</body>
<template name="newTask">
<form>
<label>What<input type="text" name="what" placeholder="gimme an action"/></label>
<input type="submit" value="Go"/>
</form>
<!--
{{> inputAutocomplete settings=settings id="msg" class="input-xlarge" placeholder="action"}}
-->
</template>
<template name="currentTask">
<form>
<label>What<input type="text" name="what" placeholder="gimme an action"/>{{activeTask.what}}</label>
<div>4h 15m</div>
<input type="submit" value="Stop"/>
</form>
</template>
And here is the JavaScript file:
tasks = new Mongo.Collection('tasks');
if (Meteor.isClient) {
Template.body.helpers({
activeTask: function() {
var task = tasks.findOne(
{
endAt: null
},
{
sort: {
startAt: -1
}
}
);
console.log(task);
return task;
}
});
Template.newTask.events({
'submit' : function(event) {
event.preventDefault();
var now = Date.now();
var what = event.target.what.value;
tasks.insert({ what: what, startAt: now, endAt: null });
}
});
}
It successfully adds a new document into the database and logs this in the helper activeTask. One step later it logs no task at all. It has gone. But why?
If you don't have the package autopublish (https://atmospherejs.com/meteor/autopublish) installed, you need to create a publication (client-side) and subscription (server-side):
if (Meteor.isServer) {
Meteor.publish('tasks', function () {
return tasks.find();
});
}
if (Meteor.isClient) {
Meteor.subscribe('tasks');
}
I've also explained working with collections in a recent blog article.

How to access nested template attributes?

I successfully implemented a form with quill wysiwyg but now I want to create a component to reuse it. This is my working implementation:
<template name="form">
<form>
<div id="toolbar"> ... html with toolbar buttons </div>
<div id="editor"></div>
<input type="submit" value="save"/>
</form>
</template>
Template.form.rendered = function () {
this.quill = new Quill('#editor', {
modules: {
'toolbar': { container: '#toolbar' },
'link-tooltip': true
},
theme: 'snow' }
);
}
Template.form.events({
'submit form': function(e, tmpl) {
e.preventDefault();
var html = tmpl.quill.getHTML();
// code to save the form data
}
This is what I want to make it reusable. My questions are inside the code:
<template name="form">
<form>
{{> editor }}
<input type="submit" value="save"/>
</form>
</template>
<template name="editor">
<div id="toolbar"> ... html with toolbar buttons </div>
<div id="editor"></div>
</template>
Template.editor.rendered = function () {
this.quill = new Quill('#editor', {
modules: {
'toolbar': { container: '#toolbar' },
'link-tooltip': true
},
theme: 'snow' }
);
// How can I pass quill to the parent template?
}
Template.form.events({
'submit form': function(e, tmpl) {
e.preventDefault();
// How can I access quill variable on the nested template, so I can
// call quill.getHTML()?
}
Here's a pattern I use to solve this sort of problem. Define a class called Editor and a template editor. The intention is that the data context inside editor will be an instance of Editor.
function Editor() {
this.quill = null;
}
Template.editor.rendered = function () {
this.data.quill = new Quill(...);
}
<template name="editor">...</template>
Inside form's created callback, create an Editor and store it on the template instance. Then when you call out to the editor template, pass in the Editor instance as the data context.
Template.form.created = function () {
this.editor = new Editor();
}
Template.form.helpers({
editorInstance: function () {
return Template.instance().editor;
}
});
<template name="form">
<form>
{{> editor editorInstance }}
<input type="submit" value="save"/>
</form>
</template>
You can then define methods on the Editor prototype which can be called by the form:
Editor.prototype.getTextAsHTML = function () {
return this.quill && this.quill.getHTML();
}
Template.form.events({
"submit form": function(e, tmpl) {
e.preventDefault();
var html = tmpl.editor.getTextAsHTML();
// ...
}
}
This is a nice way to abstract the details of the editor so that the form doesn't need to know about it. You can reuse the editor and if you ever want to change it, you just have to make sure getTextAsHTML works the same.

Resources