VueJS pass parameters through the router next() - vue.js

I want to pass the last route into my router when I'm in /login to redirect the user when is logged to desired route.
So the user go to /payment I redirect to /login and when the authentication is ok I want to redirect the user to payement
Here is my router.js :
import ...
Vue.use(Router)
let router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/login',
name: 'login',
component: Login
},
{
path: '/about',
name: 'about',
component: About
},
{
path: '/payment',
name: 'payment',
component: Payment,
meta: {
requiresAuth: true
}
},
{
path: '/my-account',
name: 'my-account',
component: MyAccount,
meta: {
requiresAuth: true
}
}
]
})
router.beforeEach((to, from, next) => {
console.log('Before Each Routes')
if(to.matched.some(record => record.meta.requiresAuth)) {
if (store.getters.isLoggedIn) {
console.log('Logged in')
next()
return
}
console.log(to.fullPath)
next({
path: '/login',
params: { nextUrl: to.fullPath }
})
return
} else {
console.log(to.fullPath)
next()
}
})
export default router
So I set some console.log and I got this :
if I go directly to /login, Output :
Before Each Routes
/login
Then if I go to /payment, Output :
Before Each Routes
/payment
Before Each Routes
/login
So now when I go in my login component and I use this.$route.params.nextUrl it's undefined. The next() parameter doesn't exist and I don't know why.
What I'm doing wrong ?

It looks like you're confusing two different mechanisms: params and query. Params have to be integral to the url, like /user/:id while query params are appended automatically.
You want this:
next({
path: '/login',
query: {
nextUrl: to.fullPath,
}
})
Related reading: https://router.vuejs.org/api/#route-object-properties

Tristan's approach above is the best when passing a url as a parameter. However, in normal cases we're passing something like an id so you can use this:
next({ name: 'account', params: { id: 3 } });
Add the replace option to prevent the navigation from appearing in the history:
next({ name: 'account', params: { id: 3 }, replace: true });
I'm using vue-router 3.1.6.

Related

Endless waiting while changing route in Vue.js

I'm working on a Vue.js webapp. Recently I realized then when I want to change route (going home) from a Vuex action, it takes a lot of time and never end. It take 4600 MB RAM and 70% CPU.
Here is the indicted code:
impostaSelezionabili: ({ commit,dispatch }, payload) => {
commit("associazioniSelezionabiliImpostate", payload)
const prefe = payload.prefe
if (payload.associazioni.length == 1) {
commit("associazioneScelta", payload.associazioni[0].codAssociazione)
dispatch("toolbarManager/setToolbarVisibility", true, {root: true})
router.push({ path: '/' })
}
},
Everything works perfectly without router line, when I add router.push({ path: '/' }) it gets the problem.
Is there a way to solve?
Router config / Routes:
export const router = new Router({
mode: 'history',
routes: [
{ path: '/', component: HomePage, name: "Home", meta: "Home" },
{ path: '/servizi', component: ServiziPage, meta: "Servizi" },
{ path: '/servizi/:id', component: ServizioPage, meta: "Servizi" },
{ path: '/login', component: LoginForm},
{ path: '/corsi', component: Corsi, meta: "Corsi" },
{ path: '/corsidisponibili', component: Corsi, meta: "Corsi disponibili" },
// otherwise redirect to home
{ path: '*', redirect: '/', meta: "Home" }
]
});
Make sure that your router exists and that is not an import of vue-router. You need to use the router that you constructed with the new Router().
But I think that is the best way to solve it - that navigating inside a component after a Promise returned by that action will be resolved because in the current case your action isn`t pure.

How to properly use the meta props on vue router?

I'm trying to handle route middleware of the children route, but I got this error
Uncaught TypeError: route.children.some is not a function
The documentation are only shows the example for a single route but in this case, I have a children route that needs to be restricted.
Please take a look at my router configuration:
import Vue from 'vue'
import Router from 'vue-router'
import store from './store/index'
import Home from './views/home/Index.vue'
Vue.use(Router)
let router = new Router({
mode: 'history',
base: process.env.VUE_APP_BASE_URL,
linkActiveClass: 'is-active',
linkExactActiveClass: 'is-exact-active',
routes: [{
path: '/',
name: 'home',
component: Home,
meta: {
requiresAuth: true
}
},
{
path: '/login',
name: 'login',
// route level code-splitting
// this generates a separate chunk (login.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('./views/auth/Login.vue'),
meta: {
requiresGuest: true
}
},
{
path: '/register',
name: 'register',
component: () => import('./views/auth/Register.vue'),
meta: {
requiresGuest: true
}
},
{
path: '/forgot-password',
name: 'forgot-password',
component: () => import('./views/auth/extras/ForgotPassword.vue'),
meta: {
requiresGuest: true
}
},
{
path: '/database',
name: 'database',
component: () => import('./views/database/Index.vue'),
meta: {
requiresAuth: true
}
},
{
path: '/third-parties',
name: 'third-parties',
component: () => import('./views/third-parties/Index.vue'),
meta: {
requiresAuth: true
}
},
{
path: '/editor',
name: 'editor',
meta: {
requiresAuth: true,
requiresAdmin: true,
requiresEditor: true,
},
children: {
path: ':appSlug/layout-editor/:pageSlug',
name: 'layout-editor',
component: () => import('./views/editor/Index.vue'),
}
},
]
})
router.beforeEach((to, from, next) => {
const isLoggedIn = store.getters['auth/isLoggedIn'];
// Role getters
const isAdmin = (store.getters['auth/isAdmin'] == 'admin') || (store.getters['auth/isAdmin'] == 'super-admin');
const isEditor = store.getters['auth/isEditor'] == 'editor';
// Redirect to the login page if the user is not logged in
// and the route meta record is requires auth
if (to.matched.some(record => record.meta.requiresAuth) && !isLoggedIn) {
next('/login')
}
// Redirect to the homepage page if the user is logged in
// and the route meta record is requires guest
if (to.matched.some(record => record.meta.requiresGuest) && isLoggedIn) {
next('/')
}
// Redirect to the preview page if the user is logged in
// but has no role assigned or the role is user
if (to.matched.some(record => (
record.meta.requiresAuth &&
record.meta.requiresAdmin &&
record.meta.requiresEditor)) && !isAdmin && !isEditor) {
next('/preview')
}
// Pass any access if not match two conditions above
next()
})
export default router
Could somebody please explain it? Why I getting this error and how to fix it?
Thanks in advance.
I just found the answer, kinda silly tho.. I forgot to put square brackets on the children props. Now it's working as I expected.
fix:
{
path: '/editor',
name: 'editor',
meta: {
requiresAuth: true,
requiresAdmin: true,
requiresEditor: true,
},
children: [{
path: ':appSlug/layout-editor/:pageSlug',
name: 'layout-editor',
component: () => import('./views/editor/Index.vue'),
}]
},

How to use a guard in vue to ignore the route rule?

How to use a guard to move to next rule of route instead of redirect to specific route?
for example, I have some routes:
routes: [
{ path: '/', component: Main },
{ path: '/about', component: About },
{ path: '/:product', component: Product },
{ path: '*', component: NotFoundException }
]
and in Product component I have beforeRouteEnter function like that:
beforeRouteEnter(to, from, next) {
const question = checkIfExist(to.params.product);
if (question) { next(); return;}
next();
}
if the product not exist then it should be redirect to NotFoundException component. in the stackoverflow example I see only example with redirect to specific url (like login) which is not helpful.
When I given url: '/some' then vue check if:
is / ? no => next route.
is /about ? no => next route.
is /:product ? no => next route.
display NotFoundException component.
You can reference the next route by route name.
First, name your exception route
routes: [
{ path: '/', component: Main },
{ path: '/about', component: About },
{ path: '/:product', component: Product },
{ path: '*', name: 'notFound', component: NotFoundException }
]
Then, create a variable which stores your beforeEnter Logic
const productExists = (to, from, next) => {
const question = checkIfExist(to.params.product);
if (question) { next(); return;}
next({
name: "notFound"
});
}
Add the route guard to the routes that you want to guard
routes: [
{ path: '/', component: Main },
{ path: '/about', component: About },
{ path: '/:product', component: Product, beforeEnter: productExists },
{ path: '*', name: 'notFound', component: NotFoundException }
]

Vue.js Vue-router weird behaviour on browser reload page

I do not understand my vue-router behaviour ...
In the browser, when the home page is displayed , I click on the /users link in the toolbar
The /users page is displayed correctly..
BUT If I try to reload this /users page ( click on reload browser button ... Chrome currently ) then ..
the /users page is re-displayed AND immediatly after the /home page is dislayed ... as indicated in the console log from my router.beforeEach() function
ROUTER BEFORE to: {name: "Users", meta: {…}, path: "/users", hash: "", query: {…}, …}
ROUTER non protected page: {name: "Users", meta: {…}, path: "/users", hash: "", query: {…}, …}
ROUTER BEFORE to: {name: "Home", meta: {…}, path: "/home", hash: "", query: {…}, …}
ROUTER non protected page: {name: "Home", meta: {…}, path: "/home", hash: "", query: {…}, …}
What could be the reason of this weird behaviour ?
router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Firebase from 'firebase'
import Home from '#/views/Home.vue'
Vue.use(VueRouter)
function loadView (view) {
return () => import((/* webpackChunkName: 'view-[request]' */ `#/views/${view}.vue`))
}
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/users',
name: 'Users',
component: loadView('Users')
}
...
{
path: '/',
component: Home
}
]
})
router.beforeEach((to, from, next) => {
console.log('ROUTER BEFORE to: ', to)
if (to.matched.some(record => record.meta.requiresAuth)) {
console.log('ROUTER protected page: ', to)
if (!Firebase.auth().currentUser) {
console.log('ROUTER user not authenticated')
next({ path: '/users', query: { redirect: to.fullPath } })
} else {
console.log('ROUTER user authenticated')
next()
}
} else {
console.log('ROUTER non protected page: ', to)
next()
}
})
export default router
It's a collateral effect of my firebase.auth().onAuthStateChanged((user)) funcction..
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.$router.push('/member')
} else {
this.$router.push('/home')
}
})
I should write it :
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.$router.push('/member')
} else {
this.$router.push('/users')
}
})
this function is called whenever I reload the current page...

Middleware for routes in vue

I want to deny some routes for authorized users, like login page, register page, but I don't know how to make those middlewares
Routes
routes: [
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/register',
name: 'Register',
component: Register
}
]
Function that I use in components
computed: {
isLoggedIn () {
return this.$store.getters.isLoggedIn
}
}
In your router you can do something like this.
All routes marked with meta: { requiresLogin: true} } will be checked in the BeforeEach method. Here we redirect them to the login page.
You can in principle halt the router and show a modal or whatever you like here.
Router
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from '../views/App.vue'
import Login from '../views/login.vue'
import Register from '../views/registser.vue'
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{ path: '/', name: 'app', component: App, meta: { requiresLogin: true} },
{ path: '/login', name: 'login', component: Login },
{ path: '/register', name: 'register', component: Register },
]
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresLogin)) {
if (**USER IS NOT LOGGED IN**) {
next({
path: '/login',
query: {
redirect: to.fullPath,
},
});
} else {
next();
}
} else {
next();
}
})
export default router
Create additional meta field requiresAuth in your routes to specify which route require logged user:
routes: [{
path: '/',
name: 'Dashboard',
component: Dashboard,
children: [{
path: 'settings',
name: 'Settings',
component: Settings,
meta: {
requiresAuth: true
}
}],
meta: {
requiresAuth: true
}
},
{
path: '/login',
name: 'Login',
component: Login
}
],
Then add middleware in main.js:
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
const authUser = JSON.parse(window.localStorage.getItem('authUser')) // your oauth key
if (authUser && authUser.access_token) {
next()
} else {
next({
name: 'Login'
})
}
}
next()
})
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: {
App
}
})