Navigating to route returns Maximum call stack size exceeded - vue.js

I want to navigate the user to /home once he clicks on a box, but currently the redirection does not work and I get this error:
Maximum call stack size exceeded
What is causing this error and how can I fix it?
here is my relevant html:
<router-link to="/home"> <md-button class="view-captable-btn" v-for="item in capTables" :key="item.contractAddress" v-model="capTables" #click="getCapTableId(item.contractAddress, item); getCaptableName(item.label, item)" >
<p>{{item.label}}</p>
<p class="contract-address-p"> {{item.contractAddress}}</p>
</md-button>
</router-link>
my method:
getCapTableId(contractAddress, item) {
let address = item.contractAddress
store.commit('saveCapTableAddress', address)
},
and my protected route logic :
import Vue from 'vue'
import Router from 'vue-router'
import firebase from "firebase/app"
import "firebase/auth"
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'Login',
component: Login
},
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/unauthorized',
name: 'Unauthorized',
component: Unauthorized
},
{
path: '/activity-log',
component: ActivityLog,
name: 'ActivityLog'
},
{
path: '/captables',
name: 'CapTables',
component: CapTables,
meta: {
requiresAuth: true
},
},
{
path: '*',
component: NotFound,
name: 'NotFound',
},
],
mode: 'history'
})
router.beforeEach((to, from, next) => {
const currentUser = firebase.auth().currentUser
const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
if(requiresAuth && !currentUser) next('/unauthorized')
else if (!requiresAuth && currentUser) next('home')
else next()
});
export default router
I tried using pushing the route with this.$route.push('/home') still doesn' work.

Related

Vue router - navigation guard is skipped when using router.push()

I have a Vue SPA with i18n and some views that require authentication via navigation guard.
When i am not authenticated and go to url via my browser:
examplepage.com/en/lockedpage
i get redirected to:
examplepage.com/en/login
which is good, however when i click a button that runs:
#click="$router.push(`/${$i18n.locale}/lockedpage`)"
i get in to the page even if i am not authenticated.
I want to get redirected to the login page if not authenticated
this is my router.js:
import Vue from 'vue';
import Router from 'vue-router';
import Home2 from './views/Home2.vue';
import Login from './views/Login.vue';
import Register from './views/Register.vue';
import ErrorLanding from './views/ErrorLanding.vue'
import Root from "./Root"
import i18n, { loadLocaleMessagesAsync } from "#/i18n"
import {
setDocumentLang
} from "#/util/i18n/document"
Vue.use(Router);
const { locale } = i18n
export const router = new Router({
mode: 'history',
base: '/',
routes: [
{
path: '/',
redirect: locale
},
{
path: "/:locale",
component: Root,
children: [
{
name: 'Home',
path: '',
component: Home2,
},
{
name: 'Home2',
path: '/',
component: Home2,
},
{
name: 'Login',
path: 'login',
component: Login,
},
{
path: 'register',
component: Register,
},
{
path: 'lockedpage',
name: 'lockedpage',
webpackChunkName: "lockedpage",
meta: {authRequired: true},
component: () => import('./views/LockedPage.vue')
},
{
path: '*',
component: ErrorLanding,
name: 'NotFound'
}
]
}
],
router.beforeEach((to, from, next) => {
if (to.params.locale === from.params.locale) {
next()
return
}
const { locale } = to.params
loadLocaleMessagesAsync(locale).then(() => {
setDocumentLang(locale)
const publicPages = [ `/`, `/${locale}`, `/${locale}/`];
const authRequired = !publicPages.includes(to.path);
const loggedIn = localStorage.getItem('user');
const redirect = to.path;
if (authRequired && loggedIn === null) {
if(to.meta.authRequired === false) {
next();
}
else
next({ name: 'Login', query: { redirect: redirect } });
} else {
next();
}
})
next()
});
Why does my navigationguard skip when using router.push() ?
This issue started after adding i18n, with localeredirect. so all routes comes after a locale for example: /en/.../
As Estus points out in the comments, the issue is that the first thing you're checking for is if the locales match, and if they do you're calling next() and sending the user to the page.
As outlined here:
Make sure that the next function is called exactly once in any given pass through the navigation guard. It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors.
If you need to keep the locale check between the to and from pages, you could do something like:
if (to.params.locale === from.params.locale && loggedIn) {
next()
return
}
which will check if the loggedIn variable is truthy before pushing the user to the page they're trying to navigate to.
I believe just removing the if statement that checks if the locales match would also work.

RangeError: Maximum call stack size exceeded when trying to log out

I'm making a simple app using Vue.js and vue router. I'm getting this error when trying to log out of my app:
vue-router.esm.js?8c4f:2827 Uncaught (in promise) RangeError: Maximum call stack size exceeded
at RegExp.exec (<anonymous>)
at RegExp.[Symbol.match] (<anonymous>)
at String.match (<anonymous>)
at matchRoute (vue-router.esm.js?8c4f:1636)
at match (vue-router.esm.js?8c4f:1518)
at redirect (vue-router.esm.js?8c4f:1578)
at _createRoute (vue-router.esm.js?8c4f:1617)
at match (vue-router.esm.js?8c4f:1519)
at redirect (vue-router.esm.js?8c4f:1578)
at _createRoute (vue-router.esm.js?8c4f:1617)
replace # vue-router.esm.js?8c4f:2827
logout # App.vue?234e:64
click # App.vue?4de4:34
invokeWithErrorHandling # vue.runtime.esm.js?2b0e:1854
invoker # vue.runtime.esm.js?2b0e:2179
original._wrapper # vue.runtime.esm.js?2b0e:6917
3
Here's my router.js:
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import Login from "./views/Login.vue";
import auth from "./auth";
Vue.use(Router);
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/dashboard",
name: "home",
component: Home,
beforeEnter: requireAuth
},
{
path: "/",
name: "login",
component: Login,
redirect: () => {
if (auth.loggedIn()) return "/dashboard";
else return "/";
}
},
{
path: "/users",
name: "users",
component: () => import("./views/Users.vue"),
beforeEnter: requireAuth
},
{
path: "/plans",
name: "plans",
component: () => import("./views/Plans.vue"),
beforeEnter: requireAuth
},
{
path: "/meetups",
name: "meetups",
component: () => import("./views/Meetups.vue"),
beforeEnter: requireAuth
},
{
path: "/notif",
name: "notifications",
component: () => import("./views/Notifications.vue"),
beforeEnter: requireAuth
},
{
path: "/admins",
name: "admins",
component: () => import("./views/Admins.vue"),
beforeEnter: requireAuth
},
{
path: "/about",
name: "about",
component: () => import("./views/About.vue"),
beforeEnter: requireAuth
}
]
});
function requireAuth(to, from, next) {
if (!auth.loggedIn()) {
next({
path: "/login",
query: { redirect: to.fullPath }
});
} else {
next();
}
}
Here's my logout function:
logout() {
auth.logout();
this.$router.replace("/");
}
The app is a simple dashboard for showing some stats. I'm using a custom auth using firebase etch. It was working earlier I don't know what i did to breakt it pls help!
Update I get another error when using code suggested in error, not sure what this error is about:
TypeError: Cannot read property 'name' of null
at Proxy.render (eval at ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"3092cd10-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=template&id=7ba5bd90& (app.js:1116), <anonymous>:30:55)
at VueComponent.Vue._render (vue.runtime.esm.js?2b0e:3548)
at VueComponent.updateComponent (vue.runtime.esm.js?2b0e:4066)
at Watcher.get (vue.runtime.esm.js?2b0e:4479)
at new Watcher (vue.runtime.esm.js?2b0e:4468)
at mountComponent (vue.runtime.esm.js?2b0e:4073)
at VueComponent.Vue.$mount (vue.runtime.esm.js?2b0e:8415)
at init (vue.runtime.esm.js?2b0e:3118)
at createComponent (vue.runtime.esm.js?2b0e:5978)
at createElm (vue.runtime.esm.js?2b0e:5925)
This is because when you logged out, auth.loggedIn() will return false.
So in redirect property of login route, else part execute. And you redirect to login page again, and then redirect execute again and again. and in an infinite loop you are redirecting to login page.
You have to check and not run redirect function if you are redirecting to login page. You can use beforeEnter like other routes:
function checkLogin(to, from, next) {
if (auth.loggedIn()) {
next({
path: "/dashboard",
});
} else {
next();
}
}
and in routes array:
routes: [
...
{
path: "/",
name: "login",
component: Login,
beforeEnter: checkLogin
},
...
]

Not redirecting to Login page with router.beforeEach VUEJS

I need help, I've been trying to debug this for hours this is my the whole code for my routing:
I need this to automatically redirect to the login page and it won't redirect with using the router.beforeEach and there is no error on the console.
import Vue from "vue";
import Router from "vue-router";
import store from "../store.js";
import Login from "#/views/Login.vue";
import Home from "#/views/Home.vue"
Vue.use(Router);
let router = new Router({
mode: "hash",
linkActiveClass: "open active",
scrollBehavior: () => ({ y: 0 }),
routes: [
{
path: "/home",
name: "Home",
component: Home,
meta: {
requiresAuth: true
},
children: [
]
}, {
path: "/login",
name: "login",
component: Login
},
]
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
console.log(store.getters.isLoggedIn);
if (store.getters.isLoggedIn) {
next();
return;
}
next("/login");
} else {
next();
}
});
export default router;
Any help would do.

How to correct, Maximum call stack size exceeded, vue-router?

Good day.
I have the following error:
[vue-router] uncaught error during route navigation:
vue-router.esm.js:1897 RangeError: Maximum call stack size exceeded
at String.replace (<anonymous>)
at resolvePath (vue-router.esm.js:597)
at normalizeLocation (vue-router.esm.js:1297)
at Object.match (vue-router.esm.js:1341)
at VueRouter.match (vue-router.esm.js:2461)
at HashHistory.transitionTo (vue-router.esm.js:1865)
at HashHistory.push (vue-router.esm.js:2267)
at eval (vue-router.esm.js:1952)
at router.beforeEach (index.js:116)
at iterator (vue-router.esm.js:1935)
According to the error it is in my file of routes, which I have it in the following way:
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../components/Home'
import Vehiculos from '../components/Vehiculos'
import Perfil from '../components/Perfil'
import Login from '../components/Login'
import TutorialIntroduccion from '../components/TutorialIntroduccion'
import Politicas from '../components/Politicas'
import Parqueo from '../components/Parqueo'
import Politicas from '../components/Politicas'
import Historial from '../components/Historial'
import firebase from 'firebase'
Vue.use(Router)
let tutorialVisto = localStorage.getItem("Tutorial");
const router = new Router({
routes: [
{
path: '*',
redirect: '/login'
},
{
path: '/',
redirect: '/tutorial'
},
{
path: '/tutorial',
name: 'tutorial',
component: TutorialIntroduccion,
meta: {
tutorialVisto: tutorialVisto,
autentificado: false
},
beforeEnter: (to, from, next) => {
let tutorialVisto = to.matched.some(record=>record.meta.tutorialVisto);
if (tutorialVisto)next('login');
else next();
}
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/home',
name: 'home',
component: Home,
meta: {
autentificado: true
}
},
{
path: '/parqueo/:id',
name: 'parqueo',
component: Parqueo,
meta: {
autentificado: true
}
},
{
path: '/vehiculos',
name: 'vehiculos',
component: Vehiculos,
meta: {
autentificado: true
}
},
{
path: '/perfil',
name: 'perfil',
component: Perfil,
meta: {
autentificado: true
}
},
{
path: '/politicas',
name: 'politicas',
component: Politicas,
meta: {
autentificado: true
},
},
{
path: '/historial',
name: 'historial',
component: Historial,
meta:{
autentificado: true
}
}
]
})
router.beforeEach((to, from, next) => {
let usuario = firebase.auth().currentUser; //Debe ser otra Promesa si esta autenticado o no.
let autorizacion = to.matched.some(record=>record.meta.autentificado);
let tutorialVisto = to.matched.some(record=>record.meta.tutorialVisto);
if (autorizacion && !usuario) {
next('login');
}
else if (!autorizacion && usuario) {
next('home');
}
else{
next();
}
})
export default router;
The problem arises when I am in the parking lot view and then when I log in, it does not redirect me to the vita login, but it gives me that error and stays in the same view, although it does close the firebase session. If I am in any of the other views, for example, vehicles, profile or main and then I give in closing session does not generate me error.
The session closing code is the following:
linkto(pathname) {
this.$router.push({ path: pathname })
if(pathname=="/login") {
firebase.auth().signOut().then(() => this.$router.replace('login'))
}
},
According to vue router's docs:
{
// will match everything
path: '*'
}
It is usually used to redirect to a 404 page not another route. In your case, you are calling a new route /login and it matches in * as well, which causes the loop and the Maximum call stack size exceeded.
You have multiple spelling mistakes in your next handlers. These calls accept the name of a route, and if you pass it a name of an route that does not exists, it will behave unspecified.
From what I can see is that you are trying to redirect to login, while you actually called the route Login
It happened to me too.
So after my investigation I have found if you are using Vuejs v. 2.* you have to use the vue-router of v. 2.* (not version 3).
Please see the following examaple:
package.json:
"dependencies": {
"vue": "^2.6.11",
"vue-router": "^2.8.1"
router.ts:
import Vue from "vue";
import VueRouter, { RouteConfig } from "vue-router";
import { Component } from "vue-router/types/router";
import Home from "#/views/Home.vue";
import NotFound from "#/views/NotFound.vue";
import MyPage from "#/views/MyPage.vue";
Vue.use(VueRouter);
const routes: Array<RouteConfig> = [
{
path: "/",
name: "Home",
component: Home as Component
},
{
path: "/my-page",
name: "MyPage",
component: MyPage as Component
},
{
// will match everything else
path: '*',
name: "NotFound",
component: NotFound as Component
}
];
const router = new VueRouter({
mode: "history",
routes
});
export default router;

Vue.js router only loading component from navigation and not from URL

how to solve this error in vuejs-
index.js?3672:101 Uncaught TypeError: Cannot read property 'beforeEach' of undefined
import VueRouter from 'vue-router';
Vue.use(VueRouter);
Vue.use(Router);
export default new Router({
// history:true,
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/Dashboard/dashboard',
name: 'Business Intelligence Platform',
beforeEnter: requireAuth,
component: dashboard
},
export function requireAuth(to, from, next) {
if (!formSubmit()) {
next({
path: '/',
query: { redirect: to.fullPath }
});
} else {
next();
}
}