Access Vuex mutators in navigation guards - javascript

I'm building an app with Laravel + VueJS. In order to restrict some routes, I use navigation guards. The problem is that I need to access Vuex mutators in order to know if the current user is logged in. The thing is that store is defined, but I cannot use the mutator from the router. I got this error: TypeError: Cannot read property 'commit' of undefined but as I said, store is well defined. Does someone have an idea ? Thanks !
routes
import Vue from 'vue'
import Router from 'vue-router'
import Hello from '#/components/Hello'
import Register from '#/components/Register'
import Login from '#/components/Login'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
component: Hello,
meta: {
showNavigation: true,
requireAuthentication: true
}
},
{
path: '/register',
component: Register,
meta: {
showNavigation: false,
requireAuthentication: false
}
},
{
path: '/login',
component: Login,
meta: {
showNavigation: false,
requireAuthentication: false
}
}
],
mode: 'history'
})
store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
access_token: null,
expires_in: 0
},
mutations: {
setToken (state, response) {
state.access_token = response.body.access_token
state.expires_in = response.body.expires_in + Date.now()
},
getToken (state) {
if (!state.access_token || !state.expires_in) return null
if (state.expires_in < Date.now()) this.commit('destroyToken')
return state.access_token
},
destroyToken (state) {
state.access_token = null
state.expires_in = 0
},
isAuthenticated (state) {
return this.commit('getToken') !== null
}
},
actions: {
getOauthToken (context, user) {
var data = {
client_id: 2,
client_secret: 'XXXXXXXXXXXXXXXXXXXXXXXXXX',
grant_type: 'password',
username: user.email,
password: user.password
}
Vue.http.post('oauth/token', data)
.then(response => {
context.commit('setToken', response)
})
}
}
})
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import { store } from './store'
import VueResource from 'vue-resource'
import VeeValidate from 'vee-validate'
Vue.config.productionTip = false
Vue.use(VueResource)
Vue.use(VeeValidate)
Vue.http.options.root = 'http://codex.app'
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requireAuthentication)) {
console.log(store)
console.log(store.commit('isAuthenticated'))
if (!store.commit('isAuthenticated')) {
next('/login')
} else {
next()
}
} else {
next()
}
})
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App }
})

when we commit mutations, it refers to change the state and ONLY the state.when you need more complex mutations to change the state, using actions instead.

Related

Why is router.push not working? [Vue3] [Vuex4]

I have some issues with Vue 3 and Vuex.
I'm trying to redirect users when logged in in my Vuex file, but it's not working as expected.
It's not returning any errors, it's changing a link, but not redirected to another page.
My action looks like this;
actions: {
async login(commit: any, payload: any ) {
const cookie_token = useCookies();
API.post('/login', {
email: payload.email.value,
password: payload.password.value
})
.then((response: any) => {
notif.success('Welcome back, ' + response.data.player.name)
cookie.set('user', response.data)
commit.commit('loginSuccess', response.data)
router.push({
name: 'index',
})
}).catch((e) => (
console.log(e.message)
)
)
}
},
And the router is getting files where routes are defined.
And here is my full router file:
import {
createRouter as createClientRouter,
createWebHistory,
} from 'vue-router'
import * as NProgress from 'nprogress'
// import routes from 'pages-generated'
import type { RouteRecordRaw } from "vue-router";
// Then we can define our routes
const routes: RouteRecordRaw[] = [
// This is a simple route
{
component: () => import("/#src/pages/index.vue"),
name: "index",
path: "/",
props: true,
},
{
component: () => import("/#src/pages/auth.vue"),
path: "/auth",
props: true,
children: [
{
component: () => import("/#src/pages/auth/login.vue"),
name: "auth-login",
path: "login-1",
props: true,
},
{
component: () => import("/#src/pages/auth/login.vue"),
name: "auth-signup",
path: "singup",
props: true,
},
],
},
{
component: () => import("/#src/pages/[...all].vue"),
name: "404",
path: "/:all(.*)",
props: true,
},
];
export function createRouter() {
const router = createClientRouter({
history: createWebHistory(),
routes,
})
/**
* Handle NProgress display on-page changes
*/
router.beforeEach(() => {
NProgress.start()
})
router.afterEach(() => {
NProgress.done()
})
return router
}
export default createRouter()
Have in mind that it's working on other files, and I can see that router is triggered here, but not chaning a page, only on vuex is not working. If it's not working, why there is no error?
You're creating more than one instance of Vue Router. You should export the same router instance, not a function creating a new instance each time it gets called.
The following code will likely yield the desired outcome:
import {
createRouter,
createWebHistory,
} from 'vue-router'
import * as NProgress from 'nprogress'
import type { RouteRecordRaw } from "vue-router";
const routes: RouteRecordRaw[] = [
// your routes here...
];
let router;
export function useRouter() {
if (!router) {
router = createRouter({
history: createWebHistory(),
routes,
})
router.beforeEach(() => {
NProgress.start()
})
router.afterEach(() => {
NProgress.done()
})
}
return router
}
I'm placing the router instance in the outer scope, so you always get the same instance when calling useRouter().
Consume it using:
import { useRouter } from '../path/to/router'
const router = useRouter();

Vuex sore lost when manually navigate vue-router route

ONLY ON SAFARI BROWSER.
When I manually write the url on navigation bar after logged in, ex: "http://x.x.x.x:8080/gestione", the browser loses the vuex store state (so does the gest_user module with the currentUser) and redirect to login component, I'M USING VUEX-PERSISTEDSTATE:
routes:
const routes = [
{
id: "login",
path: "/login",
name: "login",
component: Login,
meta: {
...meta.default
}
},
{
id: "home",
path: "/",
name: "homeriluser",
component: HomeUtente,
meta: {
...meta.public, authorize: [Role.user, Role.admin]
},
},
{
id: "gestione",
path: "/gestione",
name: "gestrilevazioni",
component: GestRils,
meta: {
...meta.admin, authorize: [Role.admin]
}
},
{
path: "/modifica",
name: "modificaril",
component: EditRil,
meta: {
...meta.public, authorize: [Role.user, Role.admin]
}
},
{
path: "*",
name: "page404",
component: Pagenotfound,
meta: {
...meta.public
}
}
];
my router:
import Vue from 'vue';
import VueRouter from 'vue-router';
import routes from "./router";
import store from "#/store/index"
Vue.use(VueRouter);
const router = new VueRouter({
routes,
mode: "history"
});
router.beforeEach(async (to, from, next) => {
// redirect to login page if not logged in and trying to access a restricted page
const { auth } = to.meta;
const { authorize } = to.meta;
const currentUser = store.state.gest_user;
if (auth) {
if (!currentUser.username) {
// not logged in so redirect to login page with the return url
return next({ path: '/login', query: { returnUrl: to.path } });
}
// check if route is restricted by role
if (authorize && authorize.length && !authorize.includes(currentUser.roles)) {
// role not authorised so redirect to home page
return next({ path: '/' });
}
}
next();
});
export default router;
my store:
import createPersistedState from "vuex-persistedstate";
Vue.use(Vuex);
Vue.prototype.$http = axios;
Vue.prototype.axios = axios;
const debug = process.env.NODE_ENV !== "production";
const customPersist = createPersistedState({
paths: ["gest_user", "gest_rilevazione.rilevazione"],
storage: {
getItem: key => sessionStorage.getItem(key),
setItem: (key, value) => {
sessionStorage.setItem(key, value)
},
removeItem: key => sessionStorage.removeItem(key)
}
});
const store = new Vuex.Store({
modules: {
pubblico: pubblico,
amministrazione: amministrazione,
loading_console: loading_console,
login_console: login_console,
gest_itemconc: gest_itemconc,
gest_rilslave: gest_rilslave,
gest_rilmaster: gest_rilmaster,
sidebar_console: sidebar_console,
gest_user: gest_user,
gest_newril: gest_newril,
gest_rilevazione: gest_rilevazione
},
plugins: [customPersist],
strict: debug
});
export default store;
Can anyone tell me why this happens?
You are probably using browser's local storage to persist data. Could you check if local storage is enabled in your Safari browser?

Vue-router redirecting not working on store.js dispatch function

I'am trying to use vue-router in my store.js file methods to redirect a user after performing a log in but for whatever reason it just send him back to the previous page. If i use vue-router in any of my .vue pages it works just fine.
What am i doing wrong?
here is my routes.js file
import Vue from 'vue'
import VueRouter from 'vue-router'
import login from '#/views/login'
import page2 from '#/views/page2 '
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{
path: '/',
name: 'login',
component: login
},
{
path: '/page2 ',
name: 'page2 ',
component: page2
}
]
})
Here is my store.js file
import Vue from 'vue'
import Vuex from 'vuex'
import axios from '#/axios.js'
import router from '#/routes';
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
token: ''
},
mutations: {
login (state, payload){
return state.token = payload;
}
},
actions: {
login ({ commit }, payload) {
axios.get('/login',{
auth: {
username: payload.username,
password: payload.password
}
}).then(function (response) {
commit('login', response.data['user-token'])
router.go('page2')
})
}
}
})
export default store;
router.go(n) is used to navigate in the history stack: https://router.vuejs.org/guide/essentials/navigation.html#router-go-n
Use router.push({name: "page2"}) instead.

Access store from main.js

I'm trying to access my store in my vue.js app from my main.js file. But for some reason store is undefined when I try to use it. Here is my code:
main.js
import { store } from './store/store'
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !store.getters.isLoggedIn) {
next({ path: '/' })
} else if (to.path === '/' && store.getters.isLoggedIn) {
next({path: '/dashboard'})
} else if (store.getters.isLoggedIn && !to.meta.requiresAuth) {
next({path: '/dashboard'})
} else {
next()
store.commit('CLOSE_USER_DROPDOWN')
}
})
store/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import auth from './modules/auth'
import optionDropdown from './modules/option_dropdown'
import userDropdown from './modules/user_dropdown'
import flash from './modules/flash'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
export const store = new Vuex.Store({
plugins: [createPersistedState({ paths: ['auth'] })],
state: {
},
getters: {
},
mutations: {
},
modules: {
auth,
flash,
userDropdown,
optionDropdown
}
})
But when I try to read from the store it says it's undefined. I'm not sure why this is? I'm importing the store. Does anybody have ideas?
I feel const on class is the problem.
In main.js :
import store from './store/store'
Try this in your store.js:
`
export default new Vuex.Store({
plugins: [createPersistedState({ paths: ['auth'] })],
state: {
},
getters: {
},
mutations: {
},
modules: {
auth,
flash,
userDropdown,
optionDropdown
}
})
`

Vue.js & Firebase 'User' info

I'm developing an app using Vue.js and Firebase.
I've managed to get the login working using email/password, and can successfully store the firebase.auth() user info in the Vue.js state under state.currentUser .
However, as per the Firebase guidelines, I have more information stored under a '/users' ref. Eg. /users/uid
I'm wanting to pull this data into the vuex store too (state.userMeta), so I can use it around the site, however it never works after a refresh. If I don't refresh, logout and then log back in, it populates the state fine.
Any help would be massively appreciated!
James
auth.js
import { auth, db } from '#/config/database'
import store from '#/vuex/store'
const init = function init () {
auth.onAuthStateChanged((user) => {
if (user) {
store.dispatch('setUser', user)
} else {
// User is signed out.
store.dispatch('setUser', null)
}
}, (error) => {
console.log(error)
})
}
export { init }
store.js
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import { db } from '#/config/database'
Vue.use(Vuex)
const state = {
currentUser: null,
userMeta: null
}
const mutations = {
SET_USER (state, user) {
if (user) {
state.currentUser = user
db.ref('users/' + user.uid).on('value', function (s) {
state.userMeta = s.val()
})
} else {
state.currentUser = null
state.userMeta = null
}
}
}
const actions = {
setUser ({commit}, user) {
commit('SET_USER', user)
}
}
const getters = {
currentUser: state => state.currentUser
}
export default new Vuex.Store({
state,
mutations,
actions,
getters,
plugins: [createPersistedState()]
})
App.vue
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
import * as auth from '#/config/auth'
const initApp = function initApp () {
auth.init()
}
export default {
name: 'app',
created: initApp
}
</script>
<style lang="scss" src="./assets/sass/style.scss"></style>
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import VueFire from 'vuefire'
import router from './router'
Vue.config.productionTip = false
Vue.use(VueFire)
import store from '#/vuex/store'
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App }
})
Vuex state is cleared upon page refresh.
I sorted this out using this method
In main.js
new Vue({
el: '#app',
router,
store,
created() {
Firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.$store.state.user = this.$firebase.auth().currentUser
} else {
this.$store.state.user = null
}
})
},
render: h => h(App)
})
So when there is a refresh, your state will be sync automatically.
In your components
computed: {
user() {
return this.$store.state.user
}
},
After a refresh, trying to use this.$firebase.auth().currentUser doesn't not work - but setting the state again via Auth changed seems to do the trick

Categories