Meteor How to call one template helper into another helper? - meteor

How i can access one template helper into another. I have 2 templates
Right sidebar path is
app\client\templates\shared\sidebar
my_trb path is
app\client\templates\pages\my_trb
on my_trb page i am showing list of all added memebrs in my account and same thing i need to call in sidebar helper. So is there way to call my_trb template helper into sidebar? This is helper in my_trb
Template.MyTribes.helpers({
'myTrb' () {
let tribIOwn = Meteor.user().trb_i_own;
let trb = [];
tribIOwn.forEach(function (t) {
trb.push(Trb.findOne({_id: t}));
});
return trb;
},
});
This is full code of tribes_controller.js
TrbController = RouteController.extend({
subscriptions: function() {
this.subscribe('users').wait();
this.subscribe('trb', this.params._id).wait();
},
waitOn: function () {
this.subscribe('trb',Meteor.userId());
this.subscribe('tribeArgs', this.params._id);
},
data: function () {
return Trb.findOne({_id: this.params._id});
},
// You can provide any of the hook options
onRun: function () {
this.next();
},
onRerun: function () {
this.next();
},
//onBeforeAction: function () {
// this.next();
//},
onBeforeAction: function () {
if (!Meteor.userId()) {
this.render('Splash');
} else {
if (!Meteor.user().username) {
this.render('AddUsername');
} else {
this.next();
}
}
},
action: function () {
this.render();
},
onAfterAction: function () {
},
onStop: function () {
},
editTribe: function () {
this.render('EditTribe');
}
});

For common / shared code that needs to be accessed by more than one Template it makes sense to define a global helper using Template.registerHelper.
For your helper this would look like this:
app\client\templates\shared\helpers
// import { Trb } from ....
Template.registerHelpers('myTrb', function myTrb () {
const user = Meteor.user();
if (! user) return [];
const tribIOwn = user.trb_i_own;
const trb = [];
tribIOwn.forEach(function (t) {
trb.push(Trb.findOne({_id: t}));
});
return trb
})
(Note, that I changed a bit, since Meteor.user().trb_i_own would crash if there is no logged in user.)
Now you can remove the helper on the my_trb Template and call it from my_trb and the sidebar as well.

Related

Meteor: Pulling variable from iron router to a template

I am trying to get two variable from the iron router so that I can essentially call them in my temlate such as {{user.telephone}} and {{pic.profilepic}}.
My code in the router is as follows. (Does Not Work!)
Router.route('/profile/:_id', {
name: 'profile',
template: 'profile',
data:function(){
return {
user:Info.findOne({_id:this.params._id}),
pic: Profilepics.findOne({_id:this.params._id})
};
},
subscriptions: function(){
return {
Meteor.subscribe("userInfo"),
Meteor.subscribe( "profilepic");
},
action:function (){
if (this.ready()){
this.render();
}else {
this.render('loading');
}
}
});
I able to do just one variable with the following code. i.e get {{user.telephone}}. Any chance anyone can help me get both variable instead of just one?
enterRouter.route('/profile/:_id', {
name: 'profile',
template: 'profile',
data:function(){
return {
user:Info.findOne({_id:this.params._id})
};
},
subscriptions: function(){
return Meteor.subscribe("userInfo")
},
action:function (){
if (this.ready()){
this.render();
}else {
this.render('loading');
}
}
});
If you are using the latest version of iron router, i suggest you update the code to something a bit more modern.
First you create a general app controller:
ApplicationController = RouteController.extend({
layoutTemplate: 'DefaultLayout',
loadingTemplate: 'loading_template',
notFoundTemplate: '404_template',
});
Then you start to extend it for different purposes:
ProfileController = ApplicationController.extend({
show_single: function() {
this.render('profile');
}
});
After this you can create your routes for the profile part
Router.route('/profile/:_id', {
controller: 'ProfileController',
action: 'show_single',
waitOn: function() {
return [
Meteor.subscribe("userInfo"),
Meteor.subscribe("profilepic")
];
},
subscriptions: function() {
this.subscribe("somethingyoudontneedtowaitfor", this.params._id);
},
data: function() {
if (this.ready()) {
return {
user: Info.findOne({
_id: this.params._id
}),
pic: Profilepics.findOne({
_id: this.params._id
})
};
}
}
});
It might be a bit more code, but it gives you complete control over what it does. Also, using this, while the router is waiting for the subscriptions to be ready, it displays the loading template defined above. If you don't want to display the loading, you move the subscriptions out of waiton.
Return multiple subscriptions as an array from subscriptions function,
Use return [
Meteor.subscribe("userInfo"),
Meteor.subscribe( "profilepic")
];
instead of
return { Meteor.subscribe("userInfo"), Meteor.subscribe( "profilepic"); which has {} mismatch.
In a similar situation I have
data: function() {
var gridId = this.params._gridId;
return (People.find({gridId: gridId})
&& GridLog.find({gridId: gridId}));
},
with the subscribe calls in the waitOn() handler as part of the Boolean status
waitOn: function() {
return (Meteor.subscribe('people', this.params._gridId)
&& Meteor.subscribe('gridlog', this.params._gridId) );
},
You may have more success just &&ing them together in waitOn() (as strange as that seems).

Meteor iron:router routecontroller change context of this

I have a function that checks if the user is logged in and it looks like this:
var requireLogin = function () {
if (! Meteor.user()) {
if (Meteor.loggingIn()) {
this.render(this.loadingTemplate);
} else {
this.render('accessDenied');
}
} else {
this.next();
}
};
It is a simple function and it works when i use it on a hook like this:
Router.onBeforeAction(requireLogin, {only: 'postSubmit'});
However, when i try to call it in an extended routecontroller like this:
LogInController = RouteController.extend({
onBeforeAction: function () {
requireLogin();
}
});
It does not work. However i can just paste the context of the function into onBeforeAction in the logincontroller and it will work.
LogInController = RouteController.extend({
onBeforeAction: function () {
if (! Meteor.user()) {
if (Meteor.loggingIn()) {
this.render(this.loadingTemplate);
} else {
this.render('accessDenied');
}
} else {
this.next();
}
}
});
so what do i need to do? Do i need to pass the value of this into the requireLogin function or is there a smarter way?
I believe that you can solve this problem by using javascript's bind function, which binds the function to the context:
LogInController = RouteController.extend({
onBeforeAction: function () {
requireLogin.bind(this)();
}
});
However, that might not even be necessary, if you just pass the function as value directly, thereby avoiding the redirection that may cause the change in context:
LogInController = RouteController.extend({
onBeforeAction: requireLogin
});

Meteor pub/sub issues

This below is my collection code
Competitions = new Mongo.Collection("competitions");
var CompetitionsSchema = new SimpleSchema({
year: {
type: String
},
division: {
type : String,
allowedValues: ['Elite', '1st','2nd','3rd','4th','Intro']
},
teams:{
type : [TeamSchema],
allowedValues: (function () {
return Teams.find().fetch().map(function (doc) {
return doc.name;
});
}()) //here we wrap the function as expression and invoke it
}
});
In the allowedValues function
Teams.find is empty.
In the router I am subscribing to the publication as follows
this.route('competitions', {
path: '/admin/competitions',
layoutTemplate: 'adminLayout',
waitOn: function () {
return [
Meteor.subscribe('teams')
];
}
});
This is my publish function
Meteor.publish('teams', function() {
return Teams.find({},{sort: {
points: -1,
netRunRate : -1
}});
});
Do I have to do subscription some where else as well?
Your problem is in this piece of code:
allowedValues: (function () {
return Teams.find().fetch().map(function (doc) {
return doc.name;
});
}()) //here we wrap the function as expression and invoke it
This gets called when the page loads. At that point the Teams collection will still be empty on the client side. You need to wait until the data is ready. Since you are using waitOn in iron-router, it might be enough to just move this code to the onRendered callback.

Multiple Data Contexts in router - Meteor

I'm building a meteor app and on one route I'm adding multiple data context like so -
this.route('orgPage', {
path: '/org/:title',
data: {
orgs: function () {Orgs.findOne(this.params._id)},
projects: function() {Meteor.subscribe('projects', this.params._id)}
}
The only problem is that when I try to access this data in my templates js file, I can't access the _id or any of the attributes of orgs.
I've tried several approaches, but it always returns undefined. If I use a single data context, it works perfectly. Here is the function that doesn't function properly -
Template.orgPage.events({
'click #newProject': function(e) {
$('#npModal').modal();
},
'submit #npModal form': function(e, template) {
e.preventDefault();
if(!$(e.target).find('[name=newTitle]').val()) {
var projectTitle = 'Untitled'
} else {
var projectTitle = $(e.target).find('[name=newTitle]').val()
}
var theid = this._id;
var newProject = {
title: projectTitle,
organization: theid
}
Meteor.call('project', newProject, function(error, id) {
if (error)
return alert(error.reason);
$('#npModal').modal('hide');
$('#npModal').on('hidden.bs.modal', function (e) {
Router.go('newFields', {});
})
});
});
Anyone have any ideas? Thanks!!
You have missed a return statement. function () {Orgs.findOne(this.params._id)} should be function () {return Orgs.findOne(this.params._id)}. Further more, this inside this function won't refer to what you want, so you can't use this.params. And why do you subscribe to a subscription as a data context property? Do it in the waitOn function instead.

Meteor: wainOn (Iron Route) not working

I have this issue that the rendered function is called while the elements are not yet in the DOM. Let me describe my situation. The templates looks like this:
<template name="barfoo">
<ol>
{{#each bars}}
<li item>{{title}}</li>
{{/each}}
</ol>
</template>
And the following javascript code
Template.barfoo.bars = function () {
return Bars.find({});
};
Tempalate.barfoo.rendered = function () {
var bars = Bars.find({}).fetch();
var list = $('[items]');
};
When the rendered function is called bars == list == [].
So to fix this I implemented Iron routes like this
Bars = new Meteor.Collection('bars');
// Routes
Router.configure({
layout: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound'
});
Router.map(function () {
this.route('/', {
controller: 'BarsController',
});
});
if (Meteor.isClient) {
App = {
subs: {
bars: Meteor.subscribe('bars'),
...
}
};
MainController = RouteController.extend({
template: 'barfoo',
before: function () { ... },
waitOn: function () {
return [App.subs.bars];
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
Meteor.publish('bars', function () {
return Bars.find({});
});
}
All basics, but when I go now to localhost:3000 I still get in the rendered function empty lists . Any suggestions what do wrong here ?
I assume your are working with the latest version of iron-router. If that's the case you will also need to add loading hook to your router, so:
Router.onBeforeAction('loading');
Also note that before hook is marked as deprecated.

Resources