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

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...

Related

the redirect url contains the absolute and relative path while redirection from route.beforeach

In my vue js application, I have a vue-router setup as follows: In route.beforeach I am checking whether the application is already authenticated or not, base upon that I had to redirect to login page.
let router = new VueRouter({
routes: routes,
mode: "history",
scrollBehavior: () => ({ x: 0, y: 0 }),
});
Vue.use(VueGtag, {
config: { id: process.env.VUE_GTAG }
}, router);
export default router;
router.beforeEach((to, from, next) =>
{
if (to.matched.some(record => record.meta.requiresAuth) && !(authService.myMsal.getAllAccounts().length > 0))
{
next({
name: "page-login",
query: {
redirect: to.fullPath
}
});
} else
{
next()
}
});
and in route.js it is setup as:
const routes = [
{
path: '/login',
name: 'page-login',
component: Login
},
{
path: '/',
component: () => import('layouts/MyLayout.vue'),
meta: {
requiresAuth: true,
},
children: [
{
name: 'home',
path: '',
component: () => import('components/Home.vue'),
meta: {
requiresAuth: true,
},
},
],
},
]
In router.beforeEach when the application has to redirect to page-login, it is redirected with a full path as: http://localhost:8080/http:/localhost:8080/login?redirect=%2F
it should have to be redirected to http:/localhost:8080/login, what is causing this behavior?

Why does the router link not work the first time?

I have a grpc application, there is authorization. When you start a project, you must be logged in. I decided to add under the login button if you are not registered. But the router does not work. Only at the entrance, go to the registration page. Please help to understand what is the mistake? Why is seemingly blocked?
routes.js
const routes = [
{
path: "/",
component: () => import("layouts/MainLayout"),
children: [
{
path: "",
component: () => import("pages/Index"),
meta: { requireAuth: true }
},
{
path: "/logs",
component: () => import("pages/Logs"),
meta: { requireAuth: true, admin: true }
}
]
},
{
path: "/",
component: () => import("layouts/AuthLayout"),
children: [
{
path: "/welcome",
component: () => import("pages/Auth"),
meta: { guest: true }
},
{
path: "/register",
component: () => import("pages/Register"),
meta: { guest: true }
}
]
}
];
I tried many things, like in Auth.vue:
<q-item to='/register'>Sign Up</q-item>
<router-link tag="a" :to="{path:'/register'}" replace>Go</router-link>
<span #click="callSomeFunc()">Register</span>
...
methods: {
callSomeFunc() {
this.$router.push({ path: "/register" });
}
My router-view in App.vue
for more information github repo
You have duplicate routes in your config - the path / is used on 2 routes. You should fix this.
To prevent unauthorized users to see your protected pages you can add a global navigation guard to your router through the beforeEach hook:
import VueRouter from 'vue-router';
const routes = [
{
path: "/",
component: () => import("layouts/MainLayout"),
meta: { requireAuth: true },
children: [
{
path: "",
component: () => import("pages/Index"),
},
{
path: "logs",
component: () => import("pages/Logs"),
meta: { admin: true }
}
]
},
{
path: "/login",
component: () => import("layouts/AuthLayout"),
children: [
{
path: "",
component: () => import("pages/Auth"),
},
{
path: "/register",
component: () => import("pages/Register"),
}
]
}
];
const router = new VueRouter({
routes
});
router.beforeEach((to, from, next) =>
{
if (to.matched.some(route => route.meta.requireAuth))
{
if (userNotLogged) next('/login');
else next();
}
else next();
});
export default router;
You may also consider reading a more verbose tutorial, e.g. https://www.digitalocean.com/community/tutorials/how-to-set-up-vue-js-authentication-and-route-handling-using-vue-router

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'),
}]
},

VueJS pass parameters through the router next()

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.

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