I have a route controller like so:
StudentPageFeeds = RouteController.extend({
waitOn: function() {
Meteor.subscribe('headers', this.route.name)
},
data: function() {
return Headers.findOne({});
}
});
And I have a route:
this.route('teacher', {
path: 'teacher/:_id',
data: function() {
return Meteor.users.findOne({_id: this.params._id});
},
controller: StudentPageFeeds
});
When I do this, the route data is not returned. Removing the route controller fixes the issue however. How can I get the data from the route, if I need to keep the route controller?
Related
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).
I have set up my app with Iron Router and have a 'post' page where I would like to show a single post according to its ID. However, this page does not show a post, and instead the post template renders blank (although the url and nav are working fine). Here is my code:
router.js
Router.route('postDetail', {
path: '/posts/:_id',
notFoundTemplate: 'postNotFound',
waitOn: function() {
return [
Meteor.subscribe('post')
]
},
data: function() {
var idVar = this.params._id
return posts.findOne({_id: idVar});
}
});
postDetail.html
<template name="postDetail">
{{address}}
</template>
postsPub.js
Meteor.publish('posts', function () {
return posts.find();
});
Meteor.publish('post', function (id) {
return posts.find(id);
});
It looks like your publisher needs an id. Try this in your waitOn:
Meteor.subscribe('post', this.params._id)
I was able to solve this issue by simply removing the 'post' publish function, and including the following route which refers to the 'posts' publish function instead:
Router.route('postDetail', {
path: '/posts/:_id',
notFoundTemplate: 'postNotFound',
waitOn: function() { return Meteor.subscribe('posts'); },
data: function() { return posts.findOne(this.params._id); }
});
Router._filters = {
isLoggedOut: function (pause) {
if (!Meteor.userId()) {
return this.redirect('home');
} else {
this.next();
}
},
isLoggedIn: function (pause) {
if (Meteor.userId()) {
return this.redirect('dashboard');
} else {
this.next();
}
}
};
filters = Router._filters;
Router.onBeforeAction(filters.isLoggedOut, { except: [
'home'
]});
Router.onBeforeAction(filters.isLoggedIn, { only: [
'home'
]});
I'd like to make filter in iron-router which makes redirect to 'home' when user is not logged in and to 'dashboard' if user is logged in. Everything works, but in the first case dashboard is shown for a second and then redirect is done. How can I get rid of this delay?
I would create a custom controller.
// Global Router configuration
Router.configure({
loadingTemplate: 'loading'
notFoundTemplate: 'notFound'
controller: BaseController
});
The code above says: "For all existing paths, use the BaseController"
Your BaseController should look like this
BaseController = RouteController.extend({
action: function() {
if(!Meteor.userId()) {
// this.render('home');
// this.go('home);
this.redirect('home');
}
else {
// this.render('dashboard');
// this.go('dashboard');
this.redirect('dashboard');
}
}
})
If you need more controll for each site,give your specific site a controller, which inherit from the BaseController. It should looks like this
// Global Router configuration
// Remove the controller property!
Router.configure({
loadingTemplate: 'loading'
notFoundTemplate: 'notFound'
});
Router.map(function() {
this.route('contact', {
path: '/contact',
controller: 'ContactController'
})
});
Your ContactController should looks like this
ContactController = BaseController.extend({
// Do something with this given route,
// e.g., give it a name property or so
name: 'contact',
action: function() {
}
})
For more information, check the Iron.Router guide.
https://github.com/EventedMind/iron-router/blob/devel/Guide.md#route-controllers
I have a iron route that searches for a collection item based on the url param. If it finds it, it returns the item as a data context, otherwise it renders a notFound template. The code looks like this:
this.route('profileView', {
path: list_path + '/profiles/:_id',
fastRender: true,
waitOn: function() {
if (Meteor.user()) {
return [Meteor.subscribe('singleProfile', this.params._id, Session.get("currentListId"))];
}
},
data: function() {
var profile = Profiles.findOne({
_id: this.params._id
});
if (!profile) {
this.render("notFound");
} else
return profile;
}
});
The problem is the notFound template gets loaded briefly prior to profile getting returned, although I thought the waitOn function would have handled that. What's the correct pattern to have the desired result using iron router? Thanks.
Is it possible that you forgot to configure the loading and dataNotFound hooks?
Router.onBeforeAction('loading');
Router.onBeforeAction('dataNotFound');
If you want to understand what is actually going on here, please look here.
I had to check for this.ready() in data. Updated code
this.route('profileView', {
path: list_path + '/profiles/:_id',
fastRender: true,
waitOn: function() {
if (Meteor.user()) {
return [Meteor.subscribe('singleProfile', this.params._id, Session.get("currentListId"))];
}
},
data: function() {
if(this.ready()){
var profile = Profiles.findOne({
_id: this.params._id
});
if (!profile) {
this.render("notFound");
} else
return profile;
}
}
});
The iron-router documentation describes changing routes programmatically. The example shows how to pass an argument but I am having trouble accessing this argument in a route controller extension.
In the code below, how would I access the 'baz' value in my waitOn function?
routes.js
Router.configure({
loadingTemplate: 'Loading',
notFoundTemplate: 'NotFound',
templateNameConverter: 'upperCamelCase',
routeControllerNameConverter: 'upperCamelCase',
onBeforeAction: 'loading'
});
Router.map(function () {
this.route('foo', {
path: '/',
action: function() {
Router.go('bar',{_id: 'baz'});
}
});
this.route('bar');
});
bar.js
BarController = RouteController.extend({
waitOn: function() {
// this.params._id does not work
// this._id does not work
// do work and return something;
},
data: function() {
// fetch and return something;
},
action: function() {
this.render();
}
});
Clarification: I would like to achieve this without including the parameter in a dynamic path segment. I just want to pass an argument like any other JavaScript function.
You need to have the param in your path variable
E.g for your foo path if you used
path: '/:_id'
instead of
path : '/'
The addition of :_id is a placeholder for something such as baz to be available with the this.params object.
Then the value would be available with this.params._id, your URL would also change to /baz.