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

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

Related

Return component in beforeEnter in vue router

I have the following path in my router
{
path: '/Page',
component: async () => {
const isUserLogged = await getUser()
const store = useStore()
if (userLogged && store.value1) {
return import('./pages/PublicPage/PublicPage.vue')
} else {
return import('./pages/NonPublicPage/NonPublicPage.vue')
}
},
},
}
Every time I enter this path, I need to return a different component depending on the value in the store, but the component is loaded only once.
I tried to rewrite the structure so that it uses beforeEnter as follows:
{
path: '/Page',
beforeEnter: async (to, from, next) => {
const isUserLogged = await getUser()
const store = useStore()
if (userLogged && store.value1) {
next({
component: () => import('./pages/PublicPage/PublicPage.vue'),
})
} else {
next({
component: () => import('./pages/NonPublicPage/NonPublicPage.vue'),
})
}
},
}
But this solution doesn't work. Without using a different path, I need to return a different component depending on the conditions. Is it possible to return a component in beforeEnter in next() or is there another solution to this problem?

specify condition before loading vuejs component

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 }
});

Vue Router Warning and Router.push is not Functioning

I am trying to route to another page after getting response from adonis project. Calling to post method is working. However router.push('/') is not functioning. Only login page reloaded every time when I submitted the b-from.
async login({ commit, state }) {
console.log("Login")
try {
const response = await HTTP()
.post('/admin/login', {
email: state.loginEmail,
password: state.loginPassword
})
.then(response => {
console.log("Ok")
console.log(response.data)
if (response.data == 'UserNotFoundException') {
alert('User not found')
router.push('/')
}
if (response.data == 'PasswordMisMatchException') {
alert('password not ms')
router.push('/')
}
if (response.data.token) {
console.log(response)
//commit('setToken', response.data.token)
router.push('/')
} else {
router.push('/')
}
})
console.log(response)
//return router.push('/')
} catch (error) {
console.log(error)
}
},
Routes:
routes: [
{
name: "FullLogin",
path: "/login",
component: () => import("#/views/authentication/FullLogin"),
},
{
path: "/",
redirect: "/dashboard/docs-dashboard",
component: () => import("#/layouts/full-layout/FullLayout"),
children: [
{
name: "Dashboard",
path: "/dashboard/docs-dashboard",
component: () => import("#/views/dashboards/docsDashboard"),
},
]
}
]
router.beforeEach((to, from, next) => {
next()
})
I can't figure out why router.push('/') is not routing.
According to docs:
Note: Inside of a Vue instance, you have access to the router instance as $router. You can therefore call this.$router.push.

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