am calling my template like this {{> list_items}} and for some reason it doesn't work
this is the template code
<template name="list_items">
{{#each items}}
<div class="col-sm-4 col-lg-4 col-md-4">
<div class="thumbnail">
<img src="{{previewImage}}" alt="">
<div class="caption">
<h4 class="pull-right">{{price}}</h4>
<h4>{{title}}</h4>
<p>{{description}}</p>
</div>
</div>
</div>
{{/each}}
</template>
and items is a function in the template helper that returns the documents in my collection, here is its code:
Template.list_items.helpers({
items: function(){
return Items.find({});
}
});
This is my Items collection allow rules
Items.allow({
insert: function (userId, doc) {
// the user must be logged in, and the document must be owned by the user
return true;
},
update: function (userId, doc, fields, modifier) {
// can only change your own documents
return true;
},
remove: function (userId, doc) {
// can only remove your own documents
return true;
}
});
And collection inside "lib" folder so that i can use it from the client side.
When i tried to use Items.find().fetch() i get an empty collection [] Even though i have the collection with one document inside it
Why it doesn't work? are there any required package to be added first?
solved it by making publish and subscribe
in the server
Meteor.publish('items-all', function publishFunction() {
return Items.find({});
})
in the client
Meteor.subscribe('items-all');
This will not allow you to find any data on client side.Items.find({}) will return empty docs.
Items.allow({
insert: function (userId, doc) {
// the user must be logged in, and the document must be owned by the user
return true;
},
update: function (userId, doc, fields, modifier) {
// can only change your own documents
return true;
},
remove: function (userId, doc) {
// can only remove your own documents
return true;
}
});
If you want to allow Items.find({}) allow to all routes/templates. You can publish the data on server side like :
Meteor.publish('all-Items', function(){
return Items.find({});
})
And on the client side you can subscribe the all-Items publish on inside the Meteor.startup like this :
Meteor.startup(function () {
Meteor.subscribe('all-Items');
}
Then you can access Items.find({}) on each and every routes and that will return all the docs reactively.
Don't forget to add fetch function to see on console like : Items.find({}).fetch(), It will return array of your docs.
Related
I can't for the life of me figure out why nothing shows up client-side in this meteor app. I have tried all the advise in all the related topics and nothing seems to work. I'm using msavin:mongol and I don't even see the subscription on the client at all, despite console.log() debug output indicates that it is there with the current number of entries.
/imports/api/friends.js:
export const Friends = new Mongo.Collection('friends');
Friends.deny({ insert() { return true; }, update() { return true; }, remove() { return true; } }); // access to collections only through method calls
/imports/api/server/friends.js:
import { Meteor } from 'meteor/meteor';
import { Friends } from '../friends.js';
Meteor.publish('friends.all', function(){
return Friends.find();
})
/imports/ui/pages/friends.js:
import { Friends } from '/imports/api/friends.js';
import './friends.html';
Template.friends.onCreated(function() {
this.subscribe('friends.all');
});
Template.friends.helpers({
friends: ()=>{ return Friends.find(); }
});
/imports/ui/pages/friends.html:
<template name="friends">
<h1 class="ui header">Friends</h1>
{{#if Template.subscriptionsReady}}
<h2 class="ui heder">friends list:</h2>
<div class="ui list">
{{#each friend in friends}}
<div class="item">{{friend.name}} ({{friend.email}})</div>
{{/each}}
</div>
{{/if}}
</template>
The "friends list" header shows up, so the subscriptionsReady call returns, but I don't get any data (verified that data exists in the database).
I've also tried moving the subscription into the router (using ostrio:flow-router-extra) and there the waitOn() function never returns when I add the subscription
What is going on here?
If you are missing to include your publication on the server then your client's subscription will immediately be 'ready' but there will be no error message.
This can cause a lot of confusion when creating templates with template-level-subscriptions.
In order to check if a publication exists or not, you can use on the server after start the (undocumented) server.publish_handlers array. It keeps a record of the registered publications.
Meteor.startup( () => {
console.log( Meteor.server.publish_handlers );
});
This comes in very handy, if you have designed your api in way that it keeps track of its intended publications:
friendsdef.js
// definition file for Friends collection and it's
// surrounding functionality
export const FriendsDef = {
collectionName: 'friends',
schema: { ... },
methods: { ... },
publications: {
all: {
name: 'friends.all'
}
}
}
someServerStartup.js
// make sure on startup, that all intended
// publications are registered
Meteor.startup( () => {
Object.values( FriendsDef.publications).forEach( pub => {
if (!Meteor.server.publish_handlers[pub.name]) {
throw new Error('publication should exist, but does not');
}
});
});
The same works with method_handlers for methods. Use these data structures with a well defined API and you will decrease errors of missing includes or misspelled names a lot.
I am having a bit of difficulty getting the email of the current user in Meteor.
publish.js
Meteor.publish('allUsers', function(){
if(Roles.userIsInRole(this.userId, 'admin')) {
return Meteor.users.find({});
}
});
Meteor.publish('myMail', function(){ {
return Meteor.user().emails[0].address;
}
});
profile.html
<template name="Profile">
<h1> My Profile </h1>
{{#if currentUser}}
<p>{{currentUser.profile.firstName}}</p> <p>{{currentUser.roles}}</p>
<p>{{currentUser.userEmail}}</p>
{{/if}}
</template>
profile.js
Template.Profile.helpers({
users: function() {
return Meteor.users.find();
},
userEmail: function() {
return Meteor.user().emails[0].address;
}
});
Firstname and ._id display fine, emailaddress unfortunately does not. Does anyone have a tip? thanks!
Your 'myMail publication is both redundant and incorrect. You should either return a cursor (or an array of cursors), or observe a cursor and send handle the publication lifecycle yourself (a fairly advanced feature, irrelevant to your question). You are using it a-la Meteor.methods, and you should not really user Meteor.user() in a publication anyway.
It's redundant because Meteor's accounts package publishes the current user's emails field automatically.
In your template, you are treating userEmail as an attribute of the current user, instead of calling it as a helper.
I would advise to use a guard and make sure that the user actually has an email address, something in the lines of:
JS:
Template.Profile.helpers({
users: function() {
return Meteor.users.find();
},
userEmail: function(user) {
if (user.emails && user.emails.length > 0) {
return user.emails[0].address;
}
return 'no email';
}
});
HTML:
<template name="Profile">
<h1> My Profile </h1>
{{#if currentUser}}
<p>{{currentUser.profile.firstName}}</p> <p>{{currentUser.roles}}</p>
<p>{{userEmail currentUser}}</p>
{{/if}}
</template>
I would also strongly advise against publishing all of the fields in the 'allUsers' publication, as it will expose sensitive data that should not leave the server under almost any circumstances (e.g, password data).
I have the following in server/publications.js...
Meteor.publish("users", function(){
return Meteor.users.find({}, {fields: {profile: 1}});
});
... and in my iron router route...
Router.route('/', function() {
this.layout('ConfLayout');
this.render('UserList', {
waitOn: function () {
return Meteor.subscribe("users");
},
data: function () {
return {
users: function () {
return Meteor.users.find();
}
};
}
});
});
...then in my template....
<template name="UserList">
<h1>Users</h1>
<ul>
{{#each users}}
<li>
{{#linkTo route='user.show'}}
<div>
{{profile.lastName}}, {{profile.firstName}}
</div>
{{/linkTo}}
</li>
{{/each}}
</ul>
</template>
...and it sort of works except the only user on the client is the currently logged in user. I am trying to get a list of ALL users for admins (don't worry about the for admins part for now).
What is also odd is that is I add a console.log statement to the publish function it never gets logged. However all the other publications in the same file seem to work fine. Also if I enable autopublish, then all the users show up as expected.
What an I missing here? Based on all I could find it seems like publishing specific fields should work for displaying all users in the client, but it almost seems like Meteor is ignoring any publications on Meteor.users altogether. I am using Meteor 1.1.0.3.
Any thoughts or help appreciated!
TIA
OK... not entirely sure why, but I suspect I may have been missing a "this" somewhere or something, but if I change the route to not use a function as the 2nd param and just pass options and then leave EVERYTHING else EXACTLY the same, it works...
Router.route('/', {
waitOn: function () {
return Meteor.subscribe('users');
},
data: function () {
return {
users: function () {
return Meteor.users.find();
}
};
},
template: 'UserList',
layoutTemplate: 'ConfLayout'
});
So I'd like to create a user profile listing the posts a user has made. My problem is passing each username through the router and onto Meteor.publish/subscribe. I keep getting "username undefined"
I suppose my question is: how does Iron Router know what "this.params.username" are? Should the url provide that?
Router
Router.route('userProfile',{
path: '/:username',
waitOn: function () {
return Meteor.subscribe('userprofile', this.params.username)},
data: function () {return {posts:Posts.find({username: this.params.username})};},
});
Meteor.publish
Meteor.publish('userprofile', function () {
return Posts.find({username: this.params.username});
});
Template
<template name="userProfile">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
Your routing code is correct, if you console.log the username inside waitOn or data you should get the correct value.
Router.route('userProfile', {
path: '/:username',
waitOn: function () {
console.log('waitOn', this.params.username);
return Meteor.subscribe('userprofile', this.params.username);
},
data: function () {
console.log('data', this.params.username);
return {
posts: Posts.find({username: this.params.username})
};
}
});
However, the way you fetch the parameter inside your publish function is wrong, you should rewrite your publication like this :
Meteor.publish('userprofile', function (username) {
return Posts.find({username: username});
});
The arguments you send to Meteor.subscribe after the name of the publication are passed to the publish function as parameters.
In Meteor, how can I prevent certain collection fields or certain portions of the page from being affected by the Live Updating/Re-Rendering system?
I found some answers such as {{#constant}} and {{#isolate}} but they are depreciated now.
Also reactive: false doesn't seem to work for me either.
You could try Tracker.nonreactive. That lets you access it a reactive data source non-reactively. For example:
<template name="tmplt">
The counter is {{getCounter}}.
</template>
Template.tmplt.helpers({
getCounter: function () {
return Tracker.nonreactive(function () {
return Session.get("counter");
});
}
});
Changes to the "counter" session variable will not cause tmplt to update.
When passing a database query to #each, make sure you call fetch:
// Don't do this
return Tracker.nonreactive(function () {
return Collection.find(...);
});
// Do this
return Tracker.nonreactive(function () {
return Collection.find(...).fetch();
});