specify condition before loading vuejs component - vue.js

I'm new to vuejs, I want to have a check done before the component is loaded, but I couldn't figure out how to do it.
what I want to do is if "this.$store.getters.user.id" and "this.$route.params.id" are not equal before the component is loaded
"this.$router.push({name: 'home', params: {id" : this.$store.getters.user.id}})"
{
path: '/:id',
name: 'home',
component: () => import('../Views/Admin/Home.vue'),
meta: {
guard: 'auth'
},
children: [
{
path: 'admin',
component: () => import('../Views/Admin/HomeProfile.vue'),
name: 'admin',
meta: {
guard: 'auth'
},
}
]
},
router.beforeEach((to, from, next) => {
if (store.getters.user) {
if (to.matched.some(route => route.meta.guard === 'guest')) next({name: 'home'})
else next();
} else {
if (to.matched.some(route => route.meta.guard === 'auth')) next({name: 'login'})
else next();
}
})

If you need to run this function before every route in your application, you could use router's beforeEach function to check that.
router.beforeEach((to, from, next) => { }.
If this is only for one or some routes, you could set the property beforeEnter to the route.
https://router.vuejs.org/guide/advanced/navigation-guards.html#per-route-guard
In your beforeEach function, you need to make the validation you said you want.
if(this.$store.getters.user.id !== to.params.id)
next({
name: 'home',
params: { id: this.$store.getters.user.id }
});

Related

How get the param from url on Vue.js and use it in router file?

I have router file, which contains all my routes.
Here is an example on one route:
path: '/events/:step',
children: [
{
path: '',
name: 'event.step',
components: {
default: Event,
sidebar: EventSidebar
}
}
],
props: {
default: ({ params, query: { id } }) => ({ id, ...params })
},
components: {
header: () => import('NavBar'),
default: () => import('Event')
},
async beforeEnter(to, from, next) {
if (step === 'login') { // can't find step
// do something
}
next()
}
I need to get the step param from route and if it is login do something in beforeEnter function.
How can I get it?
To get params from route you need to use to.params or from.params, if you want to access path you can get it from to.path or from.path depends what you need.
More info on https://router.vuejs.org/api/#routelocationnormalized
You can register global before guards using router.beforeEach:
router.beforeEach((to, from, next) => {
if (['Login', 'Signup'].includes(to.name) && logged_in)
next({ name: 'Home' })
else next()
})
https://router.vuejs.org/guide/advanced/navigation-guards.html

How to get around vue router infinite redirection error?

Getting this error as I want to check in router.beforeEach if there is a sessionToken already in storage and if not then redirect to Login where I could retrieve it:
Detected an infinite redirection in a navigation guard when going from "/" to "/login". Aborting to avoid a Stack Overflow. This will break in production if not fixed.
My code in router.js
router.beforeEach((to, from, next) => {
if(ENV == 'development') {
let sessionStorage = storage.sessionStorageGet('_sessionToken')
if (sessionStorage === null) next({ name: 'Login' })
else next()
}
})
const routes = [
{
path: '/login',
name: 'Login',
component: () => import('../views/login'),
meta: {
requiresAuth: false
}
},
{
path: '/private',
... private route config,
meta: {
requiresAuth: true
}
}
];
router.beforeEach(async (to, from, next) => {
if (ENV == 'development') {
if (to.matched.some(record => record.meta.requiresAuth)) {
const sessionStorage = storage.sessionStorageGet('_sessionToken')
if (sessionStorage) {
next();
} else {
router.push({ name: 'Login' });
}
} else {
next();
}
}
});

How can I redirect to a specific route from a children using beforeEnter

According to the route configuration below, my application should redirect to '/login' if the user is not authenticated :
const ifAuthenticated = (to, from, next) => {
if(Store.getters.isAuthenticated) {
next();
return;
}
else
{
next({ path: '/login' });
}
}
export default new Router({
routes: [
{
path: '/login',
name: 'Login',
component: DsLogin
},
{
path: '/',
name: 'home',
component: DsHome,
beforeEnter: (to, from, next) => {
ifAuthenticated(to, from, next);
},
},
{
path: '/other',
name: 'other',
component: DsOther,
beforeEnter: (to, from, next) => {
ifAuthenticated(to, from, next);
},
},
{
path: '/demand-history',
name: 'demand history',
component: DsDemandHistory,
beforeEnter: (to, from, next) => {
ifAuthenticated(to, from, next);
},
redirect: '/demand-history/1/all/all/all',
children: [
{
path: ':page/:type/:state/:owner',
name: 'demand history filtered',
props: true,
beforeEnter: (to, from, next) => {
ifAuthenticated(to, from, next);
}
}
]
}
]
})
It works well when i'm navigating to path '/' or '/other'.
But when i'm navigating to the path '/demand-history/1/all/all/all', I get redirected to '/demand-history/1/all/all/login'
using next({ name: 'Login' }) does not work either
How should I manage to get redirect to '/login' as well ?
Thx
The redirection was not initiate by the method ifAuthenticated but upstream in my code.
An Interceptor caught a 401 error and redirect to login using Router.push('login')
Altering the code with Router.push({ name: 'Login' }) solved my problem.
You can return the name of that route return {name: 'Login'}.
P.S. The names of your other routes are all lowercase except Login so maybe anyone reading this can recheck their route names.

Dynamic root url structure in Vue with vue-router, route guard & Vuex

I have a vue-router that looks like this:
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
children: [
{
{
path: 'main',
name: 'main',
component: () => import(/* webpackChunkName: "main" */ './views/main/Main.vue'),
children: [
{
path: 'dashboard',
name: 'main-dashboard',
component: () => import(/* webpackChunkName: "main-dashboard" */ './views/main/Dashboard.vue'),
},
...
There are route guards in place so that once a user is logged in they are directed to /BASE_URL/main/dashboard.
public beforeRouteEnter(to, from, next) {
routeGuardMain(to, from, next);
}
public beforeRouteUpdate(to, from, next) {
routeGuardMain(to, from, next);
}
const routeGuardMain = async (to, from, next) => {
if (to.name === 'main') {
next({ name: 'main-dashboard'});
} else {
next();
}
};
I'm storing user_id and account_id in a Vuex state and I'd like to be able to create a url structure like:
BASE_URL/<account_id>/dashboard
But I'm having trouble accessing the account_id from the store (I have getters setup to get the relevant params) and passing it as a parameter during the redirect in the route guard (its null / undefined, so I think I need to await somewhere??).
I can set up dynamic urls for paths which don't have a route guard, but not sure how to do it with them in place.
I've read through the vue-router docs, but can't work it out.
Please can anyone suggest how I can achieve the target url structure? Apologies my frontend skills are lacking and I'm new to Vue.js
Thank you!
Found a solution similar to this link:
Accessing Vuex state when defining Vue-Router routes
const startRouteGuard = async (to, from, next) => {
await dispatchCheckLoggedIn(store);
if (readIsLoggedIn(store)) {
if (to.path === '/login' || to.path === '/') {
if (store.getters.userMembership.account_id === null) {
const watcher = store.watch(store.getters.userMembership.account_id, account_id => {
watcher(); // stop watching
next({ name: 'main', params: { account_id: account_id}});
});
} else {
const account_id = store.getters.userMembership.account_id;
next({ name: 'main', params: { account_id: account_id}});
}
} else {
next();
}
} else if (readIsLoggedIn(store) === false) {
if (to.path === '/' || (to.name as string).startsWith('main')) {
next({name: 'login'});
} else {
next();
}
}
};

Infinite loop with vue router beforeEach and children paths

When i use beforeEach with children paths debug console show this error: vue-router.esm.js?8c4f:2079 RangeError: Maximum call stack size exceeded
import Vue from 'vue'
import VueRouter from 'vue-router'
import LoginMixin from '#/mixins/LoginMixin.js'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: require('#/views/Home.vue').default,
},
{
path: '/login',
name: 'login',
meta: { layout: 'centered' },
component: () => import('#/views/Login.vue'),
},
{
path: '/register',
name: 'register',
meta: { layout: 'centered' },
component: () => import('#/views/Register.vue'),
children: [
{
path: 'user',
component: () => import('#/components/RegisterForm.vue'),
},
{
path: 'company',
component: () => import('#/components/CompanyForm.vue'),
}
]
},
]
//creamos la instancia router modo history(urls amigables)
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
if (to.path != '/login' || to.path != '/register/user' && LoginMixin.methods.loginMixinCheckAuth() == false) {
//if not logead and join to other page distinc of login or register redirect to login
next('/login')
}
else {
next()
}
})
I dont know what is bad, the syntaxis is fine and function LoginMixin.methods.loginMixinCheckAuth() is working good (i tested without the function and result is the same).
Hmm at first glance I'd try to make this convoluted if in your beforeEach method simpler. Try to add something like requiresAuth: true to the meta of all your routes that require a logged in user.
In a sense you want something like this in your routes:
// ...
{
path: '/users/:userId(\\d+)/edit/',
name: 'EditUser'
props: true,
meta: {
requiresAuth: true, // <-- add this meta flag against which you check later in beforeEach
},
component: () => import(/* webpackChunkName: "user-edit" */ '#/views/UserEdit.vue'),
},
// ...
And this in your beforeEach:
router.beforeEach((to, from, next) => {
if (to.matched.some((record) => record.meta.requiresAuth)) { // <-- check for requiresAuth here
// assuming your login mixin works
// if I were you I'd store some JWT in localStorage and check that somehow in a vuex getter
if (!LoginMixin.methods.loginMixinCheckAuth()) {
next('/login')
} else {
next()
}
} else {
next()
}
})
To answer this in full would be kinda bulky so go and check out how I did that using meta here and implemented a beforeEach rule here