FlowRouter.route('/', {
action: function(params) {
if (!Meteor.user()) {
console.log("User is logged out."); // User is logged out.
console.log(Meteor.user()); // undefined
FlowLayout.render("welcome", { content: 'home' });
} else {
// It never comes down this path.
FlowLayout.render("dashboard", { content: 'noteList' });
}
}
});
It’s a pretty simple use case. I want to render one template or the other depending on whether or not the user is signed in.
However it always goes down the anonymous user path despite being logged in properly.
Try checking for “Meteor.userId()” instead of “Meteor.user()”. That works for me. I think Meteor.user() only has a value once the user data has been loaded from the server and Meteor.userId() always has a value if the user is authenticated because it’s stored locally (just my guess, not sure that’s how it actually works). You could also wrap it in a Tacker.autorun so that it switches automatically when the user logs in/out.
@coniel Awesome, so I changed it to use Meteor.userId() and it’s rendering the correct layout and template!
It’s not reactive though, meaning if I log in it does not render the dashboard#notelist layout/template. Any ideas how I can achieve this? I’m fairly new to Meteor and especially new to Flow-Router.
How can I make it switch layouts/template combo automatically if the user is signed in or not?
As soon as you need to protect other routes, you will end up making all your routes reactive using Tracker.autorun but the whole point of flow router is being non-reactive and predictable.
Instead, handle logged in/out template switching within your layout.
Good point. I use FlowRouter’s groups and triggers to achieve something similar:
MainController = FlowRouter.group();
PublicController = MainController.group();
AppController = MainController.group({
triggersEnter: [function(context, redirect) {
if (!Meteor.userId()) {
// Used to come back to the requested route after successful login
Session.set("loginRedirectContext", context);
redirect('/login');
}
}]
});
AppController.route('/some-protected-route', {...});
Basically all of the routes which require login are part of the AppController group, so it doesn’t require any extra work. PublicController is used for routes which don’t require authentication. They are both “children” of MainController, in case I was to add some global functionality.
Although I just realised that with this approach, if the user has two tabs open and logs out in one of them, they will not be redirected to/shown the login view, instead a messed up version of the current view.
Yeah, I looked at using Triggers to manage login state, and as they only run on the way in and non-reactive, they can’t be used to manage redirects if you’re already viewing a route.
I wanted to thank you guys for your input. I refactored my layout and router files and they are much easier to reason about with no reactivity in them. They also work exactly how you’d expect! No more Tracker.run etc.
a layout is in essence a template and you can compose them however you like
by checking within the templates the user existence and deciding what to
show
After read Flow Router and Blaze Layout documentation, I have no idea how to handle this situation since Flow Router do not recommend to check user status in Flow Router ACTION.
Ya I have read this before posting here and I do understand that the checking should be done in template level. As my example code in my previous post, I show example to check the true/false to decide which LAYOUT to render.
But what I don’t understand about the concept is, I know I need to call BlazeLayout.render to place the template into the Dynamic area.
So this part is what I don’t understand, I try to call BlazeLayout.render from Template.Layout1.onCreated() but I get a bunch of error message at console.
The error message in console:
Exception in defer callback: RangeError: Maximum call stack size exceeded
at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:2214:12)
at Object.Blaze._fireCallbacks (http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:1951:9)
at Object.Blaze._createView (http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:1969:9)
at Object.Blaze._materializeView (http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:2014:9)
at Object.Blaze.render (http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:2313:9)
at Object._render (http://localhost:3000/packages/kadira_blaze-layout.js?hash=493d22b2043f66d6b3694baa790b62a701aaec33:204:11)
at http://localhost:3000/packages/kadira_blaze-layout.js?hash=493d22b2043f66d6b3694baa790b62a701aaec33:80:19
at Object.Meteor.startup (http://localhost:3000/packages/meteor.js?hash=ae8b8affa9680bf9720bd8f7fa112f13a62f71c3:860:7)
at Object.render (http://localhost:3000/packages/kadira_blaze-layout.js?hash=493d22b2043f66d6b3694baa790b62a701aaec33:71:10)
at .<anonymous> (http://localhost:3000/app/app.js?hash=561a67a48dcc27dba8f5b17e193c782e657989af:80:15)
Ok, it seems from the code that you are rendering Layout1 and asking the router to render Layout1 into Layout1 which creates a recursion hence the callstack error.
create two different layouts, have your router render the appropriate layout based on “route” information and have your layouts render content or warning based on the “user” information