Vue Routing Guard TypeError - javascript

I am trying to guard home page and route user to login page if he/she is not signed in.
To do that I made I made router object so that I can use beforeEach() function.
But I get this error:
This error occurs after I try to make a constant object of router.
router.js is:
import Vue from 'vue';
import Router from 'vue-router';
import firebase from 'firebase';
import Home from './views/Home.vue';
import Signup from './components/auth/Signup.vue';
import Login from './components/auth/Login';
Vue.use(Router);
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home,
meta: {
requiresAuth: true,
},
},
{
path: '/signup',
name: 'Signup',
component: Signup,
},
{
path: '/login',
name: 'Login',
component: Login,
},
],
});
// router guards
router.beforeEach((to, from, next) => {
// check to see if routh require auth
if (to.matched.some(rec => rec.meta.requiresAuth)) {
// check state of user
const user = firebase.auth().currentUser;
if (user) {
next();
} else {
next({ name: 'Login' });
}
} else {
next();
}
});
This is is in main.js file.
import Vue from 'vue';
import firebase from 'firebase';
import router from './router';
import App from './App.vue';
Vue.config.productionTip = false;
const app = null;
// Wait for firebase init the user
firebase.auth().onAuthStateChanged(() => {
// init the app if not created
if (!app) {
new Vue({
router,
render: h => h(App),
}).$mount('#app');
}
});

Add the below changes
Add this line to last in router.js
export default router;
Add In main.js
import router from './router'; (path should point to your router.js)
new Vue({
router,
....
....
})

Related

VueJS i18n Routes 404 Page

The Idea
Let me first tell you the idea, user enter "domain.com" user will get redirected to "domain.com/en" where is set by default to the english language, after that user can navigate throughout the website for example to "domain.com/en/about-us/".
My Issue
I can't figure out how to set up the routing for the "domain.com/wrong-page" where is also the global i18n parameter that i'm waiting for or "domain.com/wrong-language/corect-page" so the user can get the appropriate 404 page that i want.
My Set Up
Router file
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import i18n from '../i18n'
Vue.use(VueRouter)
const routes = [
{
path: '/',
redirect: `/${i18n.locale}`
},
{
path: '/:lang',
component: {
render(c) { return c('router-view') }
},
children: [
{
path: '',
name: 'Home',
component: Home
},
{
path: 'about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/*',
name: '404',
component: () => import(/* webpackChunkName: "404" */ '../components/404.vue')
}
]
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
Main.js file
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import i18n from './i18n'
import LanguageSwitcher from "#/components/LanguageSwitcher.vue";
import NavigationTopMenu from "./components/NavigationTopMenu.vue";
import Footer from "./components/Footer.vue";
Vue.component('language-switcher', LanguageSwitcher)
Vue.component('navigation-top-menu', NavigationTopMenu)
Vue.component('footer-g', Footer)
Vue.config.productionTip = false
// use beforeEach route guard to set the language
router.beforeEach((to, from, next) => {
// use the language from the routing param or default language
let language = to.params.lang;
if (!language) {
language = 'en'
}
// set the current language for i18n.
i18n.locale = language
next()
})
new Vue({
router,
store,
i18n,
render: h => h(App)
}).$mount('#app')
So, another developer reached out to me, the answer was pretty straight forward we can implement a custom regex for the lang to limit what can be matched with.
:lang
needs to be
:lang(en|fr|es)
another solution is to configure the navigation guard further and redirect to the following error page.

Watch changes in $route object - Vue Router

I'm doing a project of small CRM. In the login form, I have a component that shows an alert message when email or password is incorrect. When someone is trying to login incorrectly, then type the correct info and then logout, the message still appears unless the page is refreshed.
I tried to solve that within watch by accessing $route, so every time the route is changed, I clear the state of the message.
Alert.vue:
<template>
<div :class="'alert ' + alert.type">{{alert.message}}</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
computed: mapState({
alert: state => state.alert
}),
methods: mapActions({
clearAlert: 'alert/clear'
}),
watch: {
$route (to, from){
console.log('inside $rout');
this.clearAlert();
}
}
};
</script>
main.js:
import Vue from 'vue';
import { store } from './_store';
import { router } from './_helpers';
import App from './components/App';
import './css/main.css';
new Vue({
el: '#app',
router,
store,
render: h => h(App)
});
router.js:
import Vue from 'vue';
import Router from 'vue-router';
import Dashboard from '../components/Dashboard.vue';
import LoginPage from '../components/LoginPage.vue';
import UserPage from '../components/UserPage.vue';
Vue.use(Router);
export const router = new Router({
mode: 'history',
routes: [
{ path: '/app', component: Dashboard },
{ path: '/login', component: LoginPage },
{ path: '/app/user-info', component: UserPage },
{ path: '*', redirect: '/app' }
]
});
router.beforeEach((to, from, next) => {
const allowedPages = ['/login'];
const authRequired = !allowedPages.includes(to.path);
const loggedIn = localStorage.getItem('user');
if (authRequired && !loggedIn) {
return next('/login');
}
next();
})
I tried to do both methods in documentation https://router.vuejs.org/guide/essentials/dynamic-matching.html
For some reason, the $route isn't recognized & I can't access it.
I should also mention that in my main.js I import the router.js file which imports Router from 'vue-router' & instantiates it, so $route should be accessible from all components.
can someone shed some light on why?
link to my project: repo
The $route watcher setup you have is correct, and your component has access to $route, as can be seen if you log it in mounted().
The problem is that the watcher is in Alert.vue, which is a component that is on a page being navigated away from, so it gets destroyed, preventing the watcher being invoked. If you move the $route watcher to a component that is always kept alive (e.g., App.vue), you'll see that it works correctly.

vue-router showing blank page when built

I'm asking for help. I use vuejs to make my application. Everything works perfectly. But I do the npm run build, I extract the dist folder and I open index.html, I have a blank page, and when I look in the console, I have no errors.
main.js
import Vue from "vue";
import Vuex from "vuex";
import router from "./router";
import App from "./App.vue";
import vuetify from "./plugins/vuetify";
import store from "./store";
import {
ValidationObserver,
ValidationProvider,
extend,
localize
} from "vee-validate";
import fr from "vee-validate/dist/locale/fr.json";
import * as rules from "vee-validate/dist/rules";
// install rules and localization
Object.keys(rules).forEach(rule => {
extend(rule, rules[rule]);
});
localize("fr", fr);
// Install components globally
Vue.component("ValidationObserver", ValidationObserver);
Vue.component("ValidationProvider", ValidationProvider);
Vue.config.productionTip = false;
//load vue-moment
Vue.use(require("vue-moment"));
//Load vuex
Vue.use(Vuex);
//Load vueRouter
new Vue({
router,
vuetify,
store,
render: h => h(App)
}).$mount("#app");
router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Professeur from "../components/Professeur";
import Matiere from "../components/Matiere";
import Dashboard from "../components/Dashboard";
import Filiere from "../components/Filiere";
import Salle from "../components/Salle";
import Shedule from "../components/Shedule";
import SheduleLine from "../components/SheduleLine";
import Login from "../components/Login";
import Home from "../components/Home";
Vue.config.productionTip = false;
Vue.use(VueRouter);
const router = new VueRouter({
mode: "history",
routes: [
{
path: "/dashboard",
name: "dashboard",
component: Dashboard,
meta: {
requiresAuth: true
},
children: [
{
path: "personnel/professeurs",
name: "p_professeur",
component: Professeur
},
{
path: "",
name: "home",
component: Home
}
]
},
{
path: "/login",
name: "login",
component: Login,
meta: {
guest: true
}
}
]
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
let user = JSON.parse(localStorage.getItem("_GET_TOKEN"));
if (!user && !user.token) {
next({
name: "login"
});
} else {
next();
}
} else {
next();
}
});
export default router;
App.vue
<template>
<v-app>
<router-view/>
</v-app>
</template>
<script>
export default {
name: 'app',
}
</script>
Once I compile, I have no errors but a blank page.
Thanks for any help. I tried without the router view, I manage to launch the index.html once compiled for production and I have a rendering.
You're using history mode for your router, which means you'll access your pages with paths like /login or /dashboard or /dashboard/personnel/professeurs, which are the only routes you declared.
/ or /index.html does not display anything because the router doesn't know what they are.
However, in order to have history mode working, you cannot just have a static server. The server has to know that a request to /dashboard should return the index.html file.
If you used VueCLI, the docs here might be helpful:
If you are using Vue Router in history mode, a simple static file server will fail. For example, if you used Vue Router with a route for /todos/42, the dev server has been configured to respond to localhost:3000/todos/42 properly, but a simple static server serving a production build will respond with a 404 instead.
To fix that, you will need to configure your production server to fallback to index.html for any requests that do not match a static file. The Vue Router docs provides configuration instructions for common server setups.
If you don't want to deal with this, or don't have a server enabling you to do this, you can switch history to hash mode in your router. Your routes will be accessible at /index.html#/dashboard and so on.
If you are running into this issue (as I was) in 2022 with a serverless vue 3 application and vuex, you can configure the hash-histroy like so
import { createRouter, createWebHashHistory } from 'vue-router'
import { type RouteRecordRaw } from 'vue-router'
import { Admin, Welcome } from '/#/views'
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Welcome',
component: Welcome
},
{
path: '/admin',
name: 'Admin',
component: Admin
}
]
const router = createRouter({
history: createWebHashHistory(), // <--- this is important
routes
})
export { router }
See also: docs
router/index.js :
import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
}
]
const router = createRouter({
history: createWebHashHistory(process.env.BASE_URL),
routes
})
export default router
main_folder/vue.config.js
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false,
publicPath: ''
})
Important: use publicPath: '' and createWebHashHistory
That is all. You can now build. But remember that your links will appear as /index.html#/dashboard.

How to export Router instance in Vue.js 2

I'm creating a Router instance in order to implement a routing system in my app. So, I'm doing it in such a way:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},
]
})
But I also need to implement a .beforeEach() hook on my Router instance. What's the workaround?
I find the way like:
router.beforeEach((to, from, next) => {
// ...
});
But I guess in my case it won't be correct? What's the proper way of doing it?
Solved:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},
]
})
Implementing .beforeEach() hook on router instance:
router.beforeEach((to, from, next) => {
if(to.meta.requiresAuth) {
if(store.state.session.authenticated) {
next();
}
else {
next('/admin/login');
}
}
else {
next();
}
});
Exporting the instance:
export default router;

Access vuex store in before Vue instance is initialized

I'd like to check if the user is validated before entering routes. I'm using vue-router's beforeEach to tackle this. But I realize that I can check the vuex store before the vue instance is initialized.
Main.js
import Vue from "vue";
import Vuetify from 'vuetify';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
import VeeValidate from 'vee-validate';
import store from '../store/store.js';
import App from '../app.vue';
import axios from 'axios';
import progressBar from '../plugins/progress-bar';
import { routes } from '../router-config';
import { sync } from 'vuex-router-sync';
import 'vuetify/dist/vuetify.min.css'
Vue.use(VeeValidate)
Vue.use(VueRouter)
Vue.use(Vuetify)
Vue.use(Vuex)
Vue.config.productionTip = false
axios.defaults.headers.common['Accept'] = 'application/json'
document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(document.createElement('app'))
const router = new VueRouter({
routes,
mode: 'hash',
saveScrollPosition: true,
});
sync(store, router)
router.beforeEach((to, from, next) => {
debugger;
if (to.meta.requiresAuth && store.getters.isLoggedIn) {
next({ path: '/' })
} else if (to.path === "/") {
next({ path: '/dashboard'})
} else {
next()
}
});
const app = new Vue({
el: 'app',
router,
store,
axios,
render: h => h(App),
template: '<App/>',
components: {
App,
}
});
})
How can I access this so that I can do something like this this.$store.getters.isLoggedIn? Am I thinking of this the right way?
You don't need this.$store. You have store. Just use store.
store.getters.isLoggedIn
this.$store is just a reference to store that you can use inside Vue components. But anywhere you import the store you have access to everything you need.

Categories

Resources