How can I access the name of the current route in meteor when using meteor-router? - meteor

I'm building an app using meteor and meteor router, and I would like to make a template helper for checking if the route is a specific one ({{#ifRouteIs login}}{{/ifRouteIs}}).

I had the same issue. Building on your answer, I found a working solution. It needs to go in the client side of Meteor.
Handlebars.registerHelper('ifRouteIs', function (routeName, options) {
if (Meteor.Router.page() === routeName) {
return options.fn(this);
}
return options.inverse(this);
});

According to meteor-router's README, you can get the current page with Meteor.Router.page(), so the helper might look like this:
Handlebars.registerHelper('ifRouteIs', function (routeName) {
return Meteor.Router.page() === routeName;
});

Related

How to handle subscription in Meteor / Iron Router

whats the bestway to handle subscription based data. For example, you have a game where you have to create the character first before you can do any other things. Currently I thougth I can try to handle it with a onBeforeAction filter. So I have a global controller for every route that needs a the character.
DefaultController = LayoutController.extend({
onBeforeAction : function() {
var currentCharacter = Character.getCurrent.call({});
if(currentCharacter === undefined) {
this.render('CharacterCreate');
} else {
this.next();
}
},
waitOn() {
this.subscribe('characters.owned');
}
});
You have a route like this:
Router.route('/game', { controller: 'DefaultController' });
The problem is until the the collection is loaded the game template will shown. Is there a better approach like this? And another problem when a route needs a character it throws an exception until the subscription is loaded.
Just use a loading hook while the subscriptions are being loaded.
loading(){
this.render('myLoadingTemplate');
}
The loading hook is run automatically while waiting for subscriptions to be ready.
You might find my post on building a clean router.js file useful.

Run code in specific part of URL in Iron Router

I have an application which makes heavy use of features, separated by specific users, which have different roles.
The problem is that I want to restrict access to some templates, if, for instance, the user is not an Admin.
Currently, I have this:
Router.route('createUser', {
path: '/admin/users/',
onBeforeAction: function() {
if(!isAdmin()) {
Router.go('/');
}
this.next();
}
});
But, specifying that if(isAdmin()) call to every other route is a pain. I want to know if there is any other easy and less error prone way to do it.
Maybe some regex magic would do, but I don't seem to find any examples of use.
First i will recommend you to read this meteor:common-mistakes on the profile editing part
So i will recommend you to better use the alanningroles-meteor package.
Is super easy to use, here is a Online DEMO and the Source Code if you have doubts.
On the router level you can create an onBefore hooks like this.
isAdmin = function(){
var currentUser = Meteor.user()
isUserSuperAdmin = Roles.userIsInRole(currentUser,'Super-Admin'); //using alaning roles.
if(isUserSuperAdmin){ //or use isAdmin();
this.next();
}else{
this.render('accessDenied')
}
}
Router.onBeforeAction('accessDenied', {only: ['admin','otherAdminRoute',etc]});
You can have an onBeforeAction hook combined with only for all routes like so:
var isAdmin = function() {
// Whatever logic you have for checking admin
if (!admin) {
Router.go("/");
}
this.next();
}
Router.onBeforeAction(isAdmin, {
only: ["admin/users"] // Specify other admin templates here
});

Durandal: How to route away from current view within that view's activate() function?

I have the following:
function activate(routeData) {
// make dataservice call, evaluate results here. If condition is met, reroute:
if (true){
router.navigateTo("#/someRoute");
}
alert ("should not be shown");
}
The alert is getting hit however, and then the view changes.
How do I fully navigate away from the current item and prevent any further code in that vm from being hit?
Update:
I tried using guardroute but I have to activate the viewModel to call the dataservice that returns the data that determines whether or not I should re-route. Using guardroute totally prevents the dataservice from getting called (since nothing in the activate function will get hit).
I also tried returning from the if block but this still loads the view / viewAttached / etc so the UX is glitchy.
The following worked for me in Durandal 2.0:
canActivate: function() {
if(condition)
return {redirect: 'otherRoute'};
return true;
}
activate: // Do your stuff
It's mentioned in the documentation: http://durandaljs.com/documentation/Using-The-Router.html
Here's #EisenbergEffect answer to a quite similar discussion in google groups.
Implement canActivate on your view model. Return a promise of false,
then chain with a redirect.
You might want to give #JosepfGabriel's example (discussion) a try in Durandal 1.2. Check the correct router syntax for your Durandal version, you might have to substitute it with something like router.navigateTo("#/YourHash", 'replace').
canActivate: function () {
return system.defer(function (dfd) {
//if step 2 has a problem
dfd.resolve(false);
})
.promise()
.then(function () { router.navigate("wizard/step1", { trigger: true, replace: true }); });
}
However this is NOT working in Durandal 2.0 and there's a feature request https://github.com/BlueSpire/Durandal/issues/203 for it.
You can't call redirect into the active method.
You can override the guardRoute method from router, to implement redirections.
You can do somehting like that:
router.guardRoute= function(routeInfo, params, instance){
if(someConditios){
return '#/someRoute'
}
}
You can return a promise, true, false, the route to redirect... You can find more information about that in the next link: http://durandaljs.com/documentation/Router/
Rainer's answer was pretty good and works for me adding this small fix.
Inside the then() block simply call the navigation like this
setTimeout(function() { router.navigateTo('#/YOUR DESTINATION'); }, 200);
that should fix your problem. The setTimeout does the trick. Without it the newly navigated page catches the old NavigationCancel from the previous one.
Adding a return in your if (true) block should fix this.
function activate(routeData) {
if (true){
router.navigateTo("#/someRoute");
return;
}
alert ("should not be shown");
}

Meteor: redirect a user if already logged in

I'm using meteor-router, and I'd like to redirect a user to /user if he requests / and he is already logged in.
As expected, this just renders the user_index template rather than changing the URL:
Meteor.Router.add
'/': -> if Meteor.userId() then 'user_index' else 'index'
I want to do something like this:
Meteor.Router.add
'/': -> if Meteor.userId() then Meteor.Router.to '/user' else 'index'
update 6/4/14:
This question is no longer relevant, and iron-router should be used instead.
meteor-router is now deprecated. Instead use iron-router which can redirect based on logged in status using:
Router.configure({layoutTemplate: 'mainLayout'});
Router.map(function() {
this.route('splash', {path: '/'});
this.route('home');
});
var mustBeSignedIn = function(pause) {
if (!(Meteor.user() || Meteor.loggingIn())) {
Router.go('splash');
pause();
}
};
var goToDashboard = function(pause) {
if (Meteor.user()) {
Router.go('home');
pause();
}
};
Router.onBeforeAction(mustBeSignedIn, {except: ['splash']});
Router.onBeforeAction(goToDashboard, {only: ['splash']});
Example taken from: Meteor.js - Check logged in status before render
--OR--
Use the accounts-entry package. From their site:
Ensuring signed in users for routes
Use AccountsEntry.signInRequired(this) to require signed in users for
a route. Stick that in your before hook function and it will redirect
to sign in and stop any rendering. Accounts Entry also tracks where
the user was trying to go and will route them back after sign in.
You're looking for a filter -- here is a sample from the docs:
Meteor.Router.filters({
'checkLoggedIn': function(page) {
if (Meteor.loggingIn()) {
return 'loading';
} else if (Meteor.user()) {
return page;
} else {
return 'signin';
}
}
});
// applies to all pages
Meteor.Router.filter('checkLoggedIn');
According to this issue it looks like redirects are not part of meteor-router, and may not be. For now I ended up working around the issue. If the project changes to accommodate redirects I'll update my answer, or someone else can post another answer.
update 1/23/13:
I switched to using mini-pages, which correctly deals with this case and includes a lot of great functionality like layouts.
Meteor Router lets you directly access the response object, so you can just do a 302 redirect. Something like the following will work:
Meteor.Router.add("/test/:_id", (id) ->
this.response.writeHead '302', {'Location': '/blah/' + id}
)
You can do this by using a standard filter and wrapping the redirect in a defer object.
Meteor.Router.filters({
requireLogin: function(page) {
if(! (Meteor.loggingIn()|| Meteor.user()) ){
Meteor.defer(function () {
Meteor.Router.to('/login');
});
}
return page;
}
Meteor.Router.filter('requireLogin', {except: 'login'});

How to debug template in Meteor/handlebars?

According to this blog post, I should register a helper to better debug handlebars templates, but is not working:
ReferenceError: Handlebars is not defined
So, how can I {{debug}} in Meteor/handlebars?
This is the helper function I use for debugging in my own projects:
Template.registerHelper("debug", function(optionalValue) {
console.log("Current Context");
console.log("====================");
console.log(this);
if (optionalValue) {
console.log("Value");
console.log("====================");
console.log(optionalValue);
}
});
You can then call it in your templates with {{debug}} and it displays the context you are currently in. Read more at http://docs.meteor.com/#/full/template_registerhelper.
In Meteor 0.4.0 you register handlers like this:
Template.myTemplate.helpers({
helper: function () {
// some code here
console.log(arguments);
}
});
There is no need to call Handlebars directly.
Make sure that you register your helper in client (or shared) meteor code.
Handlebars.registerHelper('helper', function() {
// Do stuff
});
This should be callable via {{helper}} in your templates.
For the sake of completeness: you can also use
Template.registerHelper('helper', helperFunc);
instead of Handlebars.regsterHelper('h',f);
A small reason this is better is that then your app won't need that much refactoring if you decide somewhere down the road that you want to use something else instead of Handlebars(i.e. Spacebars, the real name of meteors adaption) like jade for meteor.
This is really a comment to the accepted answer. Looking forward to one day hit 50 rep.

Resources