Meteor - Flowrouter: generic vs variable route - meteor

I want to display posts for different cities, defined by cityId:
FlowRouter.route("/:cityId", {
name: 'postList',
action: function() {
console.log(FlowRouter.getParam("cityId"));
return BlazeLayout.render('mainLayout', {
top: 'header',
body: 'postList'
});
}
});
Alongside with that I of course have generic routes like 'admin', 'signup' and so on.
But when I go to /signup, the postList route gets activated, treating 'signup' word as a city id, and 'signup' is logged in console.
Defining route like FlowRouter.route("/postList/:cityId") is not an option.

Actually, you need to control route definition order.
define the /signup route before the generic one: /:cityId

Related

How to change meteor router paths/slugs without reloading the template?

I have two router paths, one is /topic/:postId and one is /topic/:postId/:commentId. Both paths are pointing to the template "topic".
The first path opens the template with a list of all the post's comments. Whenever I select a comment, I filter some contents on the page based on the comment and I want the route to change to the second path (allowing users to copy the link to this filtered page directly), but I want meteor to stay on the same template and not reload the page.
In short, how can I change the URL/slugs without reloading the page?
Edit: These are my routes pointing to the same template and I'd like to jump between them without (noticeable) reload. I left out waitOn and multiple data lines for simplicity' sake:
Router.route("/topic/:postId", {
name: "Topic",
data: function () {
return {
content: "topic",
post: this.params.postId
};
}
});
Router.route("/topic/:postId/:commentId", {
name: "Comment",
data: function () {
return {
content: "topic",
post: this.params.postId,
comment: this.params.commentId
};
}
});

My router doesn't work as expected

this is the router code
Router.route('screens', {
path: '/screenshots/:_id',
template: 'screens',
onBeforeAction: function(){
Session.set( "currentRoute", "screens" );
Session.set("screenshots", this.params._id);
this.next();
}
});
this is the helper for screenshots template
Template.screens.helpers({
ss: function () {
var screenshots = Session.get("screenshots");
return Products.findOne({ _id: screenshots});
}
});
and am calling it here
<h4>Click to view the Screenshots
When i click to view the screenshots URL, the URL should be this /screenshots/:_id based on my router configuration, but what i see in the browser is /screenshots/ without the _id and the page shows 404 - NOT FOUND.
Is it possible to create nested routes?
because before i click on the link that executes the above route. i will be in this route
Router.route('itemDetails', {
path: '/item/:_id',
template: 'itemDetails',
onBeforeAction: function(){
Session.set( "currentRoute", "itemDetails" );
Session.set("itemId", this.params._id);
this.next();
}
});
and this route works fine i can see the item _id, is it possible to create another route inside it that has for example this path /item/:_id/screenshots?
I have the _id stored in Session.get("itemId"). Is it possible to call it in the path of the route somehow?
I tried '/item' + '/screenshots' + '/' + Session.get("itemId") but didn't work
or there is other way to solve it?
The problem is not with the code in the question, the 404 page is occurring due to it not being passed an id into the path, the browser says /screenshots/ and not /screenshots/randomId because it is only being passed that from the link.
As per additions to the question and chat with Behrouz: Because the value is stored in session we can use
Template.registerHelper('session',function(input){
return Session.get(input);
});
to register a global template helper called session which can be called with {{session session_var_name}} and create the link as below:
<h4>Click to view the Screenshots

Do routes with same controller subscribe to server n times or just once?

I have a tabs with four tab, each has a route with same controller.
All four tabs share the same data, menu, but use different part of the data.
Every time I click a tab, will it do a subscribe to the server?
For example, the first time I click tab1, it will contact server and get the data menu, then I click tab2, will it contact server again to fetch data menu even I have already gotten the data?
If so, how can I avoid this? Maybe I should redesign the code, is there any good ideas?
MenuController = RouteController.extend({
layoutTemplate: 'menuLayout',
waitOn: function () { return Meteor.subscribe('menu', this.params._id); },
data: function () { return Menu.findOne({_id: this.params._id}) },
});
this.route('/menu/tab1', {
name: 'menu.tab1',
template: 'MenuTab1',
controller: MenuController,
});
this.route('/menu/tab2', {
name: 'menu.tab2',
template: 'MenuTab2',
controller: MenuController,
});
this.route('/menu/tab3', {
name: 'menu.tab3',
template: 'MenuTab3',
controller: MenuController,
});
this.route('/menu/tab4', {
name: 'menu.tab4',
template: 'MenuTab4',
controller: MenuController,
});
This has changed somewhat as IR has matured. I believe in the current implementation, if you change between routes which make the same subscription with the same parameters, the subscription will not be stopped and started again. In other words, switching between tabs should not start and stop the subscription (assuming this.params._id remains constant).
You can prove (or disprove) this by adding a console.log('here') to the first line of your menu publisher. When you switch tabs, check the command-line console. If 'here' is printed only once, you have the desired outcome.
Regardless of the outcome, subs-manager is the generally accepted solution for caching subscriptions between routes.

Using Meteor, useraccounts-core ensureSignedIn plugin won't except '/' route

I am trying to use the ensureSignedIn plugin on all routes except for a front 'home' page that has buttons to login to separate parts of the site.
Here's my route for 'home':
Router.route('/', function () {
this.render('home');
});
Here's the line for the plugin and exceptions:
Router.plugin('ensureSignedIn', {
except: ['home', 'atSignIn', 'atSignUp', 'atForgotPassword']
});
Both snippets are from my lib/routes.js file, if that makes a difference.
I've tried adding different route names in the except: portion, and they get correctly excepted, but I can't for the life of me get the 'home' route to not show "Must be logged in".
I've googled and read through gitHub issues and haven't seen anyone else with this problem, so it's probably something I'm doing wrong and not a bug with useraccounts or iron-router.
Set the name of the / route to root, then add that route name to the ensureSignedIn settings:
Router.route('/', {
name: 'root',
template: 'home',
action: function() {
this.render();
}
});
Router.plugin('ensureSignedIn', {
except: ['root', 'atSignIn', 'atSignUp', 'atForgotPassword', 'atResetPwd']
});

Iron Router template not registered on redirect

I have this simple check if user is logged in and if not - redirect to register page
Router.map(function () {
this.route('home', {
path: '/',
onBeforeAction: function (pause) {
if (!Meteor.user()) {
this.render('register');
pause();
}
}
});
this.route('register', {path: '/register'});
});
And getting
Exception from Tracker recompute function: Error: Couldn't find a template named "register" or "register". Are you sure you defined it?
When I go directly to /register, it does work.
Any ideas why?
this.render takes template name as argument, not route name
this.render('templateName'): Render the template named 'templateName'
into the main yield {{> yield}}.
Source
Replace this.render("register") with Router.go('register')
It is also beneficial to check if user is in logging in state:
if (!(Meteor.loggingIn() || Meteor.user())) {
console.log("User is not logged in");
Router.go("register");
pause()
}
To create the templates I was using the em tool and when I did em g:route register it named the template Register - with a capital R.
Renaming it in the render: this.render('Register'); did the trick.

Resources