I'm working on an app in Meteor, let's call it meetups. I've already done basic crud and now I'm stucked with request action when a user sends a request for invite for a meetup (I use accounts-password package to handle auth, if it means anything). I want to show meetup's owner which users would like to visit this meetup, so it's how I designed it:
I created a 'Join' button in my template and it works perfectly when I make an event in my controller like this:
'click .join': function(event) {
var params = {
user: Meteor.userId(),
username: Meteor.user().username
}
toastr.success('You've send a request');
Router.go('/meetups');
}
Since I handle this events fetching user's params, it's very easy to show his username, I do it like this:
<p>{{username}} sent a request to join your meetup</p> <button class="btn-primary btn-xs yes">Ok</button> <button class="btn-danger btn-xs no">No</button>
I don't want to just show this user, I want to let meetup's owner also manage requests (that's why I created two buttons). Basically, it's just a simple crud, isn't it? That's why I created a new Mongo collection called 'Guests' and my 'invite event now looks like this:
'click .join': function(event) {
var params = {
user: Meteor.userId(),
username: Meteor.user().username
}
Meteor.call('join', params);
toastr.success('Ok');
Router.go('/meetups');
}
In case I use call function, I have a method to handle it:
Meteor.methods({
'join': function (params) {
Guests.insert(params);
}
});
I also created anothe template called guests:
<template name="guests">
{{#each guests}}
<p>{{username}} sent a request to join your meetup</p> <button class="btn-primary btn-xs yes">Ok</button> <button class="btn-danger btn-xs no">No</button>
{{/each}}
</template>
and included it in my meetups template like this: {{> guests}}.
As you can understand since that I see no usernames. I used an iteration through guests collection and try to fetch username because it worked just fine withound defining a separate collection.
So my question is how the heck can I push specific users (in my case those who clicked join button) and show their usernames? Any help would be appreciate.
<template name="guests">
{{#each guests}}
<p>{{username}} sent a request to join your meetup</p> <button class="btn-primary btn-xs yes">Ok</button> <button class="btn-danger btn-xs no">No</button>
{{/each}}
</template>
How about add guests helper in guests template?
You didn't define it.
Template.guests.helpers({
guests: function () {
return Guests.find();
}
});
Related
Main purpose of this code is, when we have data in database it should fetch and display on the browser. But i couldn't find it.
Problem is transferring data to the Server.
After running the meteor and enter some value from console of the browser,i am not able to see them back on the browser.But i am able to find them with in console by using the command "Tdos.find().fetch()",it is showing arrays that i have entered but if i am trying to find in mongodb console, we couldn't find it. Can Some one figure out my problem and where am i going wrong?
<head>
<title>simpletodos</title>
</head>
<body>
{{> todoList}}
</body>
<template name="todoList">
<h3>Todos</h3>
<ul>
{{#each tdos}}
{{> todo}}
{{/each}}
</ul>
<button class="add-todo">Add todo</button>
</template>
<template name="todo">
<li>
{{label}}
</li>
</template>
Client/Main.js
if(Meteor.isClient) {
Template.todoList.helpers({
todos: function() {
return Tdos.find();
}
});
if(Meteor.isServer) {
}
}
Server/main.js
import { Meteor } from 'meteor/meteor';
Tdos = new Mongo.Collection("tdos");
Meteor.startup(() => {
// code to run on server at startup
});
In your server, you define the collection like this:
Tdos = new Mongo.Collection("tdos");
Which means the collection in Mongo is todos, and you can list the contents with
db.todos.find()
You can insert a record in mongo using this:
db.todos.insert({label: "My first to do"})
In Meteor when you want to fetch or insert/update, you use Tdos, eg
Tdos.insert(...};
Your helper lets the data be available as an array within your code. I think you need to change that to be
todos: function() {
return Tdos.find().fetch();
}
I have a collection of People that has the fields {name, id}
I also have the field Likes that contains {user_id, foodName}
I want to create a template that will display a list of People, and the food they like. I am running an each in my template to pull all of this information from a query on the Likes collection. I want to take the queried user_id from Likes and then use it to pull the associated name of the person from the People collection.
My template looks like this:
<template name="likes">
{{#each likes_list}}
//This displays the user_id, but I want to have it display the user's name
<p>{{user_id}} likes {{foodName}}</p>
{{/each}}
</template>
My helper looks like this:
Template.likes.helpers({
likes_list: function() {
return Likes.find();
}
});
I see 2 solutions:
Add userName filed to your Likes collection and display it like
this {{userName}} in your template
Create publish function which will "join" your collections (Users and Likes). To do it use this package: https://atmospherejs.com/reywood/publish-composite
You can add a helper to return the user data context and then use it with with:
html:
<template name="likes">
{{#each likes_list}}
<p>{{#with person}}{{name}}{{/with}} likes {{foodName}}</p>
{{/each}}
</template>
js:
Template.likes.helpers({
likes_list: function() {
return Likes.find();
},
person: function(){
return People.findOne({id: this.user_id});
}
});
You could map it into a single object if you wanted to.
Template.blah.helpers({
likes: function () {
return Likes.find().map(function (doc) {
return _.extend(doc, {
user: Meteor.users.findOne(doc.user_id)
});
});
}
});
This will add the user field to the collection for you to reference
{{#each likes}}
{{user.name}} likes {{foodName}}
{{/each}}
I'm listing all the Meteor users in a template:
<template name="userList">
<ul>
{{#each users}}
<li>
{{_id}}<br>
Emails:
{{#each emails}}
{{address}},
{{/each}}
</li>
{{/each}}
</ul>
</template>
Here's my helper:
Template.userList.helpers({
users : function() {
return Meteor.users.find({});
}
});
This works, but since I'm not using usernames, I only want to list the first email address and not have to handle it with an {{#each}} in the template. Ideally, I'd have a value for users.primaryEmail, so I changed the helper to this:
Template.userList.helpers({
users : function() {
var rawUsers = Meteor.users.find({});
var users = [];
_.each(rawUsers, function(user) {
user.primaryEmail = user.emails[0].address;
users.push(user);
})
return users;
}
});
...and updated my template code to output {{primaryEmail}}, but it doesn't seem to return any users at all now. What am I missing?
Figured out that I needed to use .fetch() in order to get the results as an array & make users.emails[0] work:
var rawUsers = Meteor.users.find({}).fetch();
When I subscribe to a mongodb collection in the client and publish in the server whilst switch auto-publish off. Do I need to specify each individual find query I am declaring in my helper functions within the publish method? Or is it sufficient to just return Meteor.collection.find() in the Publish statement and that should give access to the entire collection?
Lost? Please see below
In my application I have 2 mongo collections setup. One Called 'Tables' and another called 'Rolls'.
In my client.js file I have two handlebars helper functions:
Template.tables.tableList = function(){
return Tables.find();
}
Template.tableBox.table = function(tableID){
return Rolls.find({"Roll.tableName": tableID}, {sort: {date: -1}, limit:10});
}
to correspond to my templates:
<template name="tables">
<div class="table-area">
{{#each tableList}}
{{> tableBox}}
{{/each}}
</div>
</template>
<template name="tableBox">
<table id="{{name}}" class="table table-condensed">
<tr class="n{{minBet}}">
<th>{{name}}</th>
<th> Min:</th>
<th>{{minBet}}</th>
<th>{{cPlayers}}</th>
</tr>
<tr>
<td>D1</td>
<td>D2</td>
<td>D3</td>
<td>Tot</td>
</tr>
{{#each table name}}
{{> tableRow}}
{{/each}}
</table>
</template>
<template name="tableRow">
<tr class={{rowColor Roll.dice1 Roll.dice2 Roll.dice3 Roll.total}} "bold">
<td>{{Roll.dice1}}</td>
<td>{{Roll.dice2}}</td>
<td>{{Roll.dice3}}</td>
<td>{{Roll.total}}</td>
</tr>
</template>
The first helper function returns all the Tables in the collection.
The 2nd returns the last 10 Rolls in descending order.
Using autopublish - everything works fine. My page shows all the tables and within each table the last 10 dicerolls.
When I switch autopublish off and try and setup corresponding subscribe/publish statements. It doesn't work. Only the Tables are shown - but the data from the Rolls collection is not populating my template.
Corresponding Subscribe and Publish Code:
In client.js:
Meteor.subscribe('tables');
Meteor.subscribe('rolls');
In server/publications.js:
Meteor.publish('tables', function() {
return Tables.find();
});
Meteor.publish('rolls', function() {
return Rolls.find();
});
My assumption is that it is to do with my slightly complicated query in my handlebars helper function for the rolls table? Is it not a simple subscribe to the whole collection (i.e. publish the return of Rolls.find()) and then be able to access all mongo query subsets that I define within my client? Is there something I'm missing here? Thanks for any help.
This seems like it is due to Rolls collection not being fully loaded on the client yet at the time you query for it. You can try something like:
Template.tables.tableList = function(){
return Tables.find();
}
Template.tableBox.table = function(tableID){
Deps.autorun(function () {
return Rolls.find({"Roll.tableName": tableID}, {sort: {date: -1}, limit:10});
});
}
The Deps.autorun(func) block runs the encapsulated function whenever the reactive dependencies change.
I am new to Mongo and NoSQL databases. Can someone explain the way to do a one to many join and a cycling through collections in Meteor.
For example, say I have two collections, a Post and a Comment where each comment has a postId, meaning each Post has zero or many Comments. I am interested in what would be best practice for this type of situation for Meteor specifically where you can cycle through each post and comment in a nested Handlebars call. Something like the example below:
{{#each post}}
{{title}}
{{content}}
{{#each comment}}
{{comment_text}} by {{author}}
{{/each}}
{{/each}}
Although the standard MongoDB paradigm is to denormalize data, in Meteor applications it's not uncommon to stick to the pattern of having different collections (tables) for each logical dataset.
To implement joins in Meteor webapps, you simply have to define a relation between the two collections :
var postId = Posts.insert({
title: "A post",
content: "Some content..."
});
Comments.insert({
postId: postId,
author: "Someone",
text: "Some text..."
});
Denormalizing means that you must not forget to publish the two collections, you can do as follow :
Meteor.publish("postById", function(postId){
// publish the according post...
var postCursor = Posts.find(postId);
// ...and every comments associated
var commentsCursor = Comments.find({
postId: postId
});
// you can return multiple cursors from a single publication
return [postCursor, commentsCursor];
});
This publication would send down to the client a post and all its comments, given a post._id.
Associated with correct client-side routing, you can subscribe to this publication with the post id retrieved from a URL (/posts/:_id) and display the post with all its comments.
Your template pseudo code is OK, however I would refactor it using a distinct template for each collection.
HTML
<template name="outer">
{{!-- loop through each post, the child template will
be using the current post as data context --}}
{{#each posts}}
{{> post}}
{{/each}}
</template>
JS
Template.outer.helpers({
posts: function(){
return Posts.find();
}
});
HTML
<template name="post">
<h3>{{title}}</h3>
<p>{{content}}</p>
{{!-- loop through each comment and render the associated template --}}
{{#each comments}}
{{> comment}}
{{/each}}
</template>
JS
Template.posts.helpers({
comments: function(){
// return every comment belonging to this particular post
// here this references the current data context which is
// the current post being iterated over
return Comments.find({
postId: this._id
});
}
});
HTML
<template name="comment">
<p>{{text}}</p>
<span>by {{author}}</span>
</template>