MongoDB data not appearing in Meteor template - javascript

I started my first app with Meteor and everything was going fine, until I noticed that a collection is no longer showing in a template.
This is my code:
App.js
Tasks = new Mongo.Collection("tasks");
if (Meteor.isServer) {
Meteor.publish("tasks", function () {
return Tasks.find();
});
}
if (Meteor.isClient) {
Meteor.subscribe("tasks");
Template.body.helpers({
tasks: function () {
return Tasks.find({}, {sort: {createdAt: -1}});
}
});
}
App.html
<template name="home">
<h3>Open Tasks</h3>
<ul>
{{#each tasks}}
{{> displayTasks}}
{{/each}}
</ul>
</template>
<template name="displayTasks">
<li>{{text}}</li>
</template>
Routes.js
Router.route("/", function () {
this.render("Home");
});
I've double-checked with http://meteortips.com/second-meteor-tutorial/publish-subscribe/ and MeteorJS template not showing data, not appearing and it seems that I've done everything correctly. I also tried changing the names and trying to display the tasks on different templates, but to no avail. MongoDB does have data and I can manually insert entries (using the Mongo console) that have their text fields filled out.
What else can I do to troubleshoot? Backtracing my steps hasn't helped and I'd rather avoid starting a new app from scratch.
NOTE: I'm using Iron Router.

By default, child templates don't have access to their parent's helpers. In the code above, the tasks helper has been defined for the body template, but it's needed in the home template. Try this instead:
Template.home.helpers({
tasks: function () {
return Tasks.find({}, {sort: {createdAt: -1}});
}
});
Note that you can explicitly pass a helper from a parent to a child, as seen in my answer to this question, but that's uncommon.

Related

Iron router with Meteor display data to template

I am using iron router with Meteor (latest versions). I have a template:
<template name="home">
{{#each products}}
<p>{{name}}</p>
{{/each}}
JJJJJJJJJJJJ
</template>
and in lib/router.js:
Router.configure({
layoutTemplate:'layout'
});
Router.map(function () {
this.route('home', {
path:'/',
template:'home',
data : function () {
return Products.find();
}
});
});
When I run the page, I see empty page with this JJJJJJJJJJJJ, added for test to see is it template loads.
In the Products collection are 2 items with name. I can read (select), add, remove items for this collection via WEB browser console, but the collection is not rendered in the template.
What can be the error ?
The data function of Iron Router sets the data context for the template. In your case, you are setting the data context to be a cursor but attempting to access the cursor with products, which does not exist as a helper, either registered globally or on the template itself.
There's a few ways you can fix this, but I would suggest letting the router simply determine which template to render and let the template fetch it's own data.
Adjusted router:
Router.map(function () {
this.route('home', {
path: '/',
template: 'home'
}
);
Template helper:
Template.home.helpers({
products() {
return Products.find();
}
});
Alternatively, you can use the this keyword within the template to access the current data context:
<template name="home">
{{#each this}}
<p>{{name}}</p>
{{/each}}
JJJJJJJJJJJJ
</template>
However, it is not easy to discern what is being put into this unless you can follow the flow of the data through the route to the template. This also couples this template very tightly with this route, as the route itself is determining the context of your template.
The solution is in lib/router.js, need to set attribute data like this :
data : function () {
templateData = {
products: Products.find()
};
return templateData;
}
, NOT like before - return Products.find(); .

Meteor - Not updating in real time anymore

Just started using Meteor and am loving it thus far.
I'm making a variation of the tutorial "todo" app, but with my own customization.
More or less the changes I made so far have been:
Changed directory structure to client, server, public, lib/collections folders
Made the task collection through collection2 schema rather than dynamically creating with Tasks.insert(title = text,etc etc)
So to the question.
These are my client/server files -
server.js
Meteor.publish("tasks", function () {
return Tasks.find({}, {sort: {checked: 1}});
});
client.js
// This code only runs on the client
Meteor.subscribe("tasks");
Template.task.events({
"click .toggledone": 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);
}
});
And its being displayed in the standard html
<ul>
{{#each tasks}}
{{> task}}
{{/each}}
</ul>
So basically as it is now, my server is sorting the tasks on the basis of whether it is checked (completed) or not, ascending.
It works currently, when I click a task on the list, it turns red (my configuration) and registers as completed, but the list doesn't sort automatically like it did originally (before I made the directory changes).
For it to update, I need to refresh the page which is not what I want.
I'm new to this and i think it has something to do with my publish/subscribe but I can't seem to find anything to help me online.
Can anyone point me in the right direction for this?
Thanks so much.
I think you are confused between the publication/subscription named tasks and the collection tasks for the loop on the template. When you want to render the tasks on the template, it should be returned from a helper. Consider that publication/subscription making the correct part of the database available on the client and then, you retrieve the correct data from that part to display.
Normally, I make the naming convention for the publication like the SQL query so it is easier to interpret
Meteor.publish("select-from-tasks", function () {
return Tasks.find({});
});
and then,
Meteor.subscribe("select-from-tasks");
You will need to have a helper to return the correct data, like I said above
Template.task.helpers({
tasks: function() {return Tasks.find({}, {sort: {checked: 1}});}
});

Why is the template not updating in real time?

I have this Meteor code which is meant to update a notifications' template in real time whenever an appropriate action is triggered:
~/server/app.js
Meteor.methods({
notifs: function(){
return Meteor.users.findOne({_id:this.userId}, {'profile.notifs': 1});
}
});
and:
~/client/apps.js
Template.notifs.helpers({
notifs: function(){
Meteor.call('notifs', function(err, data){
Session.set('notifs', data);
});
return Session.get('notifs');
}
});
finally:
~/public/templates/notifs.html
<template name='notifs'>
{{#each notifs}}
<p>...</p>
{{/each}}
</template>
What this code does for the moment is just listing the notifications when the user logs in, but fails to update in real time to show new notifications as actions are triggered.
New notifications show up only after a page refresh (which is, honestly, useless).
After hours of googling I give up and post this here so someone can help me, please.
Thanks in advance.
At it's core, this question is about reactivity. Because Meteor.call isn't a reactive data source (it's just a remote procedure call), the helper won't run again if the underlying data changes.
Because the necessary user document is already published (it's for the current user), the method call isn't needed. You could rewrite your helper using find (a reactive data source) like this:
Template.notifs.helpers({
notifs: function() {
return Meteor.users.findOne({_id: Meteor.userId()});
}
});
However, Meteor.user() gives you the same functionality:
Template.notifs.helpers({
notifs: function() {
return Meteor.user();
}
});
However, you don't really even need this because templates come with the {{currentUser}} helper. So you can drop the helper altogether and modify your template like this:
<template name='notifs'>
{{#each currentUser.notifs}}
<p>...</p>
{{/each}}
</template>
If you ever actually do need the result of a meteor call in a helper, you should read the answers to this question.

Meteor not outputting MongoDB query

main.html:
{{#each getRequests}}
<li>{{_id}}</li>
{{/each}}
main.js
if (Meteor.isClient) {
Meteor.subscribe('getRequests',{fbID : Meteor.user().services.facebook.id});
}
publications.js
Meteor.publish('getRequests', function(args) {
return data.find({"potentialUsers.user_id" : args.fbID});
});
I'm stuck trying to get the main.html to display the IDs from the database. The user's ID can be in multiple documents in the "data" table, nested within data.potentialUsers.user_id. What I don't understand is that when I put the query into meteor mongo (in the command line) it executes successfully.
I am fairly new to meteor myself, but reading through the docs I see these issues.
Subscribe makes the documents available to the client from the publication. You still need to write a function to deliver them to the html.
main.js
if (Meteor.isClient) {
Meteor.subscribe('getRequests',{fbID : Meteor.user().services.facebook.id});
Template.body.helpers({
getRequests: function(){
return data.find() // since you want everything the publication has.
}
})
}
Then in your html:
{{#each getRequests}}
<li>{{_id}}</li>
{{/each}}

Ember.js not re-rendering template after Model loaded

I'm learning Ember.js using a Ruby on Rails API server. I've got the routes, template, and model all setup and working - but the template is never re-rendered once the data has been loaded from the API server. I'm not getting any error messages, and I know the customer is being loaded from looking at the Ember inspector.
Customer list is supposed to be displayed after start
Customer list is being loaded correctly from the API server:
Router
// javacripts/router.js
App.Router.map(function() {
this.resource('customers', { path: "/" });
});
Customers Route
// javascripts/routes/customer_routes.js
App.CustomersRoute = Ember.Route.extend({
model: function() {
return this.store.find('customer');
},
renderTemplate: function() {
this.render('customers/index');
}
});
Customer Model
// javascripts/models/customer.js
App.Customer = DS.Model.extend({
name: DS.attr('string')
});
Customer Index Template
// javacripts/templates/customers/index.js.handlebars
<ul>
<li>start</li>
{{#each customers}}
<li>{{name}}</li>
{{/each}}
</ul>
Store
// javacripts/store.js
App.ApplicationAdapter = DS.ActiveModelAdapter.extend({
namespace: 'api/v1'
});
Instead of
{{#each customers}}
It should read either
{{#each controller}}
{{name}}
{{/each}}
or
{{#each customer in controller}}
{{customer.name}}
{{/each}}
I have recently posted two screencasts. One showing how to get started with a new application, and one showing how to setup Grunt:
https://www.youtube.com/watch?v=T-s34EVSE_0
https://www.youtube.com/watch?v=kPaHt_F3VcU
You might also get some use out of a talk I gave earlier this year as well, which goes through developing a simple application during the talk, including Ember Data.
https://www.youtube.com/watch?v=KH5RreHtaaQ
Your customers/index template is referencing a "customers" collection that doesn't exist.
Your route's model hook is returning an array of records, which makes Ember generate an Ember.ArrayController with its model set to your array of customers. It doesn't have a property called "customers", so the {{#each customers}} doesn't have anything to iterate over. If you change it to just {{#each}} (because this in this scope references the controller, which is array-like) or {{#each model}} (to explicitly access the model array of the ArrayController), it should work correctly.
Also, your renderTemplate hook in the Route is the default behavior, so you can just delete it.
Incidentally, I'd recommend just using an Ember JSBin or something while you're starting out and learning the basics, so when you need to ask for help, you can just link to the bin, and people have live code they can work with to help you out, with a minimum of effort. That low barrier to entry makes a big difference to people who are doing free work for internet points.

Categories