Root route is ignored when I add /admin route in FlowRouter - javascript

My home route works when it's by itself:
FlowRouter.route('/', {
name: 'home',
triggersEnter: [
function(context, redirect) {
var ExperimentsSub, handle, randomExperiment;
console.log('Home triggers');
ExperimentsSub = new SubsManager;
handle = ExperimentsSub.subscribe('randomExperiment');
if (handle.ready && Experiments.find.count) {
randomExperiment = Experiments.findOne;
return redirect('/experiment/' + randomExperiment._id);
}
}
],
action: function() {
console.log('Rendering home');
return BlazeLayout.render('layout', {
content: 'home'
});
}
});
But when I add in my /admin route, surfing to / routes through the admin route instead.
FlowRouter.route('/admin', {
name: 'admin',
triggersEnter: [console.log('Admin triggers'), !Roles.userIsInRole(this.userId, ['admin']) ? FlowRouter.go(FlowRouter.path('login')) : void 0],
action: function() {
console.log('Rendering admin');
return BlazeLayout.render('layout', {
content: 'admin'
});
}
});
I know this because of the console logging I'm doing. When I surf to / with both routes, the console output is Rendering admin. Why is it doing this, and how can I fix it?

The problem was in my admin route triggers. I was not assigning an array of functions. I'm not clear why this created the side effects I saw, but correcting it fixed the route.
The route with the fixed triggers property looks like this:
FlowRouter.route '/admin',
name: 'admin'
triggersEnter: [ (context, redirect) ->
console.log 'Admin triggers'
unless Roles.userIsInRole this.userId, ['admin']
redirect FlowRouter.path('login')
]
action: ->
console.log 'Rendering admin'
BlazeLayout.render 'layout', content: 'admin'

Related

Page with the authRequired meta still gets shown for a split second even when no one is logged in on Firebase

I'm new to Vue / web development, ever since I started i've had a good amount of fun but now i'm stuck.
Currently I am creating an admin dashboard with Firebase authentication. Everything seems to work like it should but there is one thing that I still don't understand.
In the Vue Router I have all the different routes set up and the dashboard is inaccessible (if not logged in to Firebase).
This is my Router Guard:
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/register",
name: "Register",
component: Register,
},
{
path: "/login",
name: "Login",
component: Login,
},
{
path: "/dashboard",
name: "Dashboard",
component: Dashboard,
meta: {
requiresAuth: true,
},
},
];
router.beforeEach((to) => {
//If route requires authentication
if (to.matched.some((rec) => rec.meta.requiresAuth)) {
//Check firebase user
auth.onAuthStateChanged((user) => {
console.log(user);
//If the user object does not exist then redirect to the /Login page
if (!user) {
router.push("/login");
}
});
}
});
If I now try to open localhost:8080/dashboard it shows the dashboard for a split second and then hops to the /login page.
If also tried it with next({name: 'Login'}) but for some reason I keep getting white pages when I use next().
Hope someone can help me.
Thanks :)
The problem is that instead of checking for a logged-in user you are adding an "event listener" auth.onAuthStateChanged.. it fires async when the authentication state changes. However you need a sync check here. The best would be to use vuex and store your user in a global state. Though if you don't use vuex at all and you need your user only here, then probably a "local" user var in the router would also work.. something like this:
let user = null
auth.onAuthStateChanged(u => {
console.log(u)
if (u) {
user = u
} else {
user = null
}
})
router.beforeEach(to => {
if (to.matched.some(rec => rec.meta.requiresAuth)) {
//Check firebase user
if (!user) {
router.push("/login");
}
}
})
It's just a concept, but it should work.. let me know :)

vue-router redirect not working on route push

I have the following router configured:
const router = new Router({
mode: 'history',
routes: [
// root
{
path: '/',
component: ComponentPage,
redirect: routePrefix.public,
children: [
// public
{
path: routePrefix.public,
component: ComponentPage,
redirect: `${routePrefix.public}/login`,
children: [
{
path: `${routePrefix.public}/login`, component: LoginPage,
}],
},
// private
{
path: routePrefix.private,
component: ComponentPage,
children: [
{
path: `${routePrefix.private}/u`, component: PrivatePage,
}],
}],
}],
});
now as you can see, there are two main parts; a public, and a private one.
Additionally I have the following navigation guard configured for authorization:
router.beforeEach((to, from, next) => {
console.log(`registered request to redirect from
'${from.fullPath}' to '${to.fullPath}'`);
if (to.fullPath.startsWith(routePrefix.private) &&
!Store.getters['auth/isAuthenticated']) {
console.log('-> reroute to public main');
next(routePrefix.public);
} else if (to.fullPath.startsWith(routePrefix.public) &&
Store.getters['auth/isAuthenticated']) {
console.log('-> reroute to private main');
next(routePrefix.private);
} else {
next();
}
});
If you're wondering what the route prefix look like, here you go:
const routePrefix = {
public: '/p', private: '/x',
};
Nothing so special.
The problem
I open the page localhost:8080/ which redirects / to /p/login as expected. After a successful login, I perform a Router.push('/') with the intention to further re-route the user once again.
The idea is that / should get redirect to /p/login again, where the navigation guard kicks in and redirects it to /x/... But it doesn't. It stays on /.
Isn't it supposed to redirect it away from the main page? How can I fix it?
I didn't find a solution to this problem. I've reached my goal by pushing to the desired destination directly instead of letting the rerouting do its magic. This works.

Redirection with iron-router and onBeforeAction on meteor app

I have a meteor app and with the package iron-router, I try to block all pages if the user is not connected except fews pages. And if nothing is specified we go on the landing page.
So in the file router.js, I have :
Router.onBeforeAction(function() {
if (!Meteor.userId()) {
Router.go('login');
} else {
this.next();
}
}, {
except: [
"login", "landing", "register", "forgotPassword"
]
});
Router.route('/', function () {
Router.go('landing');
});
But when I go on localhost:3000/ I'm redirected to login page and not to the landing page.
If I remove the onBeforeAction function, I'm redirect to the landing page.
So it must be a problem with this 2 functions but I don't know where. Maybe I need to precise the "/" in the exceptions but it doesn't work. Do you have an idea ?
You need to define the route '/' in your exceptions too, otherwise this is caught by the onBeforeAction
Try re-defining as follows
Router.onBeforeAction(function() {
if (!Meteor.userId()) {
Router.go('login');
} else {
this.next();
}
}, {
except: [
"default", "login", "landing", "register", "forgotPassword"
]
});
Router.route('/', function () {
Router.go('landing');
}, {
name: "default"
} );
In this case you name the route and then you can add it to your exception list
see http://iron-meteor.github.io/iron-router/#named-routes

Vue-router 2 changes route but does not update the view?

I have a login issue with website that uses:
Vue.js v2.0.3
vue-router v2.0.1
vuex v0.8.2
In routes.js I have a simple interceptor setup
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!router.app.auth.isUserLoggedIn) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
And in login.vue,which handles the login page logic after using Google API only for login succeeds I call this:
this.login(userData).then(
() => this.$router.push(this.redirectToAfterLogin), // Login success
() => {} // Login failed
)
mounted: function(){
if (this.auth.isUserLoggedIn){
// Let's just redirect to the main page
this.$router.push(this.redirectToAfterLogins)
}else{
Vue.nextTick(() => {
this.loadGooglePlatform()
})}}
computed: {
redirectToAfterLogin: function() {
if (this.$route.query.redirect){
return this.$route.query.redirect
}else{
return '/'
}
}
}
router.js
var VueRouter = require('vue-router')
// Router setup
export const router = new VueRouter({
linkActiveClass: "is-active",
mode: 'history',
saveScrollPosition: true,
routes: [
{ path: '', name: 'root', redirect: '/home' },
{ path: '/login', name: 'login', meta: { loadingNotRequired: true }, component: require('./pages/login.vue') },
{ path: '/logout', name: 'logout', meta: { loadingNotRequired: true }, component: require('./pages/logout.vue') },
{ path: '/home', name: 'home', title: 'Home', redirect: '/home/random', component: require('./pages/home.vue'),
children: [
{ path: 'random', name: 'random', meta: { requiresAuth: true }, title: 'Random', component: require('./pages/random.vue') }
]
}
]
})
// Redirect to login page if not logged In
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!router.app.auth.isUserLoggedIn) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // make sure to always call next()!
}
})
Now here this.login is just the call to vuex, to update the logged in user.
What happens is that after login, URL changes to /home, but the DOM does not update!
Only way that successfully changed the DOM was forcing location.reload() and that is not what I want to do, as it loses my dynamically loaded G scripts in Head.
Any idea on what to do to force the view to update DOM?
NOTE: it happens only on the first login of user, if he logs out and back-in, the redirecting is fine
Not a perfect solution may be, as it is going to recreate the component but it will work for every case when having same route & needs to update the component.
Just update the <router-view/> or <router-view></router-view> with
<router-view :key="$route.fullPath"></router-view>
Vue re-uses components where possible. You should use beforeRouteUpdate to react to a route switch that uses the same component.
I have the same problem "URL changes to /home, but the DOM does not update".
In my project, the tag "transition" maked the problem.
Hope it is helpful!
Maybe you should set the redirectToAfterLogin function into methods, like this it will be recalculated each times. The computed will be modified only if used v-model changed. To stick to the meaning of the function name, I would set the router push inside.
login.vue :
mounted: function(){
if (this.auth.isUserLoggedIn){
// Let's just redirect to the main page
// this.$router.push(this.redirectToAfterLogins)
this.redirectToAfterLogins()
}else{
Vue.nextTick(() => {
this.loadGooglePlatform()
})
}
},
// computed: {
methods: {
this.login(userData).then(
// () => this.$router.push(this.redirectToAfterLogin), // Login success
() => this.redirectToAfterLogin(), // Login success
() => {} // Login failed
),
redirectToAfterLogin: function() {
if (this.$route.query.redirect){
// return this.$route.query.redirect
this.$router.push(this.$route.query.redirect)
}else{
// return '/'
this.$router.push('/')
}
}
}
https://v2.vuejs.org/v2/guide/computed.html#Computed-Properties
https://v2.vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods
"However, the difference is that computed properties are cached based on their dependencies. A computed property will only re-evaluate when some of its dependencies have changed. This means as long as message has not changed, multiple access to the reversedMessage computed property will immediately return the previously computed result without having to run the function again."
methods vs computed and filters :
Access vue instance/data inside filter method

Meteor Iron Router doesn't call onBeforeAction if data returns null/undefined

I am using Meteor with iron-router and I'm trying to redirect the user back to the login-page if he is no logged in. But on some routes the onBeforeAction is not called. And as I discovered this has something to do with the data which is returned by the data function on the route.
If data returns null/undefined the onBeforeAction is not called and it displays the layout without the data.
If data returns i.e. an empty object it is calling the onBeforeAction and redirecting to the login-page.
1) Is this the right behaviour or is there something wrong with my route definition?
2) Is it possible that the onBeforeAction function is called before the page is rendered? Because it always show the layout/view for a short moment which is not that nice.
So, I have this route:
this.route('dashboardPortfolio', {
path: ['/dashboard/portfolio'],
layoutTemplate: 'dashboardLayout',
yieldTemplates: {
'header': {to: 'header'},
'dashboardHeader': {to: 'dashboardHeader'},
'footerMain' : {to: 'footer'}
},
notFoundTemplate: 'notFound',
loadingTemplate: 'dashboardLoading',
waitOn: function() {
return Meteor.subscribe("portfolio-edit");
},
data: function() {
var portfolio = Portfolio.findOne({user: Meteor.userId()});
if(portfolio) return portfolio;
else return {};
// return Portfolio.findOne({user: Meteor.userId()});
}
});
and my onBeforeAction:
var OnBeforeActions;
OnBeforeActions = {
loginRequired: function(route, asd, pause) {
if (!Meteor.userId()) {
this.layout('login');
this.render('login');
} else {
this.next();
}
}
};
Router.onBeforeAction(OnBeforeActions.loginRequired, {
except: ['register', 'login', 'about', 'portfolio']
});
Try replacing "except" by "only" in the next line:
except: ['register', 'login', 'about', 'portfolio']
Good luck!

Categories

Resources